24 Oct 2015

Hello everybody,

Even though there has been almost no activity on this blog for a few months I have been very busy.

Here is a simple crackme for you guys, contact me with a keygen (and preferably a small tutorial) to get listed (with a website of choice) in this list:

  1. kao
  2. Dave
  3. Nobody

Have fun!

Mr. eXoDia

Leave a comment


10 Aug 2015

Sitting at a camping with a broken toe makes you bored, very bored in fact. So bored I started to look at the camping network structure.

Scanning the environment

The first thing I noticed was the cameras with a nice little antenna hanging all over the place. In an old DefCon talk I saw the security of most IP cameras was shit, so I decided to give it a shot myself.

The camera model I am currently talking about is the ELRO C903IP.2. I reversed the firmware of another ELRO camera and it had very similar directory structures and web commands, so I believe it is safe to assume all ELRO cameras are affected.

Because I had no idea of the network layout beforehand I ran a little nmap scan to get the list of online IP addresses in the local subnet:

MacBook-Air:~# nmap -sP

Starting Nmap 6.47 ( ) at 2015-08-10 00:28 CEST
Nmap scan report for
Host is up (0.0055s latency).
Nmap scan report for
Host is up (0.00048s latency).
Nmap scan report for
Host is up (0.057s latency).
Nmap scan report for
Host is up (0.054s latency).
Nmap scan report for
Host is up (0.047s latency).
Nmap scan report for
Host is up (0.052s latency).
Nmap scan report for
Host is up (0.044s latency).
Nmap scan report for
Host is up (0.11s latency).
Nmap scan report for
Host is up (0.0028s latency).
Nmap scan report for
Host is up (0.0085s latency).
Nmap scan report for
Host is up (0.0084s latency).
Nmap scan report for
Host is up (0.021s latency).
Nmap done: 256 IP addresses (12 hosts up) scanned in 9.12 seconds

The thing that struck me was the low addresses after the gateway so I first checked those out. Turned out the lower addresses were DHCP (my MacBook was I did find a nice open printer though:

screenshot of printer

Web authentication gone wrong

After some more checking I found a login screen at This could be a camera!

screenshot of IP camera authentication screen

Trying some default stuff (admin:admin, admin:1234) etc. didn’t appear to work, so I just pressed the Cancel button:

screenshot of IP camera after cancel

Besides the lack of even a self-signed HTTPS certificate it was obvious that even the login screen had serious security issues. After the initial state of shock I decided to check out the page source code:

screenshot of IP camera login source code

check_user.cgi appears to be the page generating the HTTP authentication (which is plain text by the way). The page only shows us 401 Unauthorized and the name and version of the web server mini_httpd/1.19 19dec2003. There are some known vulnerabilities for that version, but they had no POC code for reading files so I put that on halt for the time being.

screenshot of the IP camera 401

get_status.cgi requires no authentication (wtf) and it shows some identifying information like the system version and some other status information

screenshot of the IP camera status

Since there were some links on the login page I decided to try and sign in to the camera web interface. Clicking the link and pressing cancel a few times showed the full web interface, but unfortunately the feed was black.

screenshot of the IP camera web interface

An unexpected surpise

Trying to click some of the terrible popup menus on the left (I had been a few hours on the web interface at this point) gave some more device information (obtained from the get_status.cgi), but the P2P menu showed some actually interesting stuff!

screenshot of the P2P interface in the web interface

The iframe led me to p2p.htm, which contained some GUID, a username and a password (you are kidding me right?) Just setting the input type to text with the inspector revealed the details in full glory:

screenshot of the p2p.htm page with password shown

Checking the source it turns out that get_tutk_account.cgi has no .htpasswd protection which is why it shows the password in the web interface.

screenshot of get_tutk_account.cgi

Theory in practice

Googling for a P2P IP Camera app gives this nice app that automatically gets the running cameras:

screenshot of camera list

Selecting the right camera and entering the password given by the web interface shows this nice feed by the campfire (notice me walking around with crutches):

screenshot of camera feed

The other cameras have the same vulnerability (probably the same model):

screenshot of all cameras

Going for gold

After this serious issue I couldn’t get much further with the web interface (just some directory listings, but no directory traversal or anything). I did try to access .htpasswd (read something about that for old versions of mini_httpd), but it gave a graceful 403.

Let’s try another nmap scan to see what services are running on the device:

MacBook-Air:~# nmap -sV -vv

Starting Nmap 6.47 ( ) at 2015-08-10 00:52 CEST
NSE: Loaded 29 scripts for scanning.
Initiating Ping Scan at 00:52
Scanning [2 ports]
Completed Ping Scan at 00:52, 0.00s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 00:52
Completed Parallel DNS resolution of 1 host. at 00:52, 0.02s elapsed
Initiating Connect Scan at 00:52
Scanning [1000 ports]
Discovered open port 80/tcp on
Discovered open port 23/tcp on
Increasing send delay for from 0 to 5 due to max_successful_tryno increase to 4
Completed Connect Scan at 00:52, 6.99s elapsed (1000 total ports)
Initiating Service scan at 00:52
Scanning 2 services on
Completed Service scan at 00:52, 7.00s elapsed (2 services on 1 host)
NSE: Script scanning
NSE: Starting runlevel 1 (of 1) scan.
Nmap scan report for
Host is up (0.0026s latency).
Scanned at 2015-08-10 00:52:16 CEST for 14s
Not shown: 998 closed ports
23/tcp open  telnet  BusyBox telnetd
80/tcp open  http    mini_httpd 1.19 19dec2003

Read data files from: /usr/local/bin/../share/nmap
Service detection performed. Please report any incorrect results at .
Nmap done: 1 IP address (1 host up) scanned in 14.24 seconds

There is telnet! Trying telnet asks for a login and password, but at least it is not blocking connections! Not sure how that would work out remotely, but I suspect it would connect just fine.

Trying some of the worst passwords of 2014 it appears to actually be using the worst password in the world for root access: 123456.

MacBook-Air:~# telnet
Connected to
Escape character is '^]'.

(none) login: root

BusyBox v1.12.1 (2012-11-19 22:34:42 PST) built-in shell (ash)
Enter 'help' for a list of built-in commands.


Some firmware reversing adventures led me to check in the /mnt/5350 directory (I might write something about that another time):

# ls
var     tmp     sbin    mnt     lib     home    etc     bin
usr     sys     proc    media   init    etc_ro  dev
# cd mnt
# ls
pdbmountfs  5350        mtd         bin     tmp         nfs
# cd 5350
# ls
mini_httpd.conf    modules            web                etc
user_info          usb_reset_logfile  lib

The user_info file looks interesting:

# cat user_info

Well, looks like plaintext credentials for the web interface to me. Trying it and it works perfectly fine:

screenshot of logged in web interface

Final words

So that would be about it for this blogpost. Before I finish I do want to say that this research was done just for fun and no cameras were harmed in the process. Another thing is that I had access to the local network. I think that if you isolate these camera’s on a separate subnet and make sure they are not accessible from the outside (or only accessible from a fixed IP address with firewall rules in the router) you will be fine.

After this post is published I will send a link to ELRO to inform them about the security issues discussed here. If they release a firmware update to fix these issues I will update this post.

Till next time,

Mr. eXoDia

PS For Natalia: ❤️️

Leave a comment

Extending De4dot

17 Jul 2015

Hey, what’s up everybody?

About two months ago I came across a modified version of de4dot someone made, which required me to replace my current de4dot version in it’s entirety. I did not like this and therefore I decided to work on extension support for de4dot. Basically it allows you to add new deobfuscator modules or replace the existing (sometimes outdated) ones, in a dynamic way.

In this blogpost I will explain to you how to add a simple deobfuscator for OrangeHeap. The actual deobfuscator code is not written by me, but by TheProxy. It only serves as an example of how de4dot can be extended :)

Getting started

To get started, we need to set up our development environment. For this you need Git and Visual Studio. Follow these steps to get a development environment running:

  1. Clone the repository with git clone --recursive;
  2. Copy and rename the deobfuscator.Template directory to deobfuscator.OrangeHeap;
  3. In that same directory, rename deobfuscator.Template.csproj to deobfuscator.OrangeHeap.csproj;
  4. Open the main de4dot.sln in Visual Studio 2010 or higher and add deobfuscator.OrangeHeap.csproj to the solution;
  5. Now the only thing left is to rename the output file name and namespace from deobfuscator.Template to deobfuscator.OrangeHeap.

Coding the deobfuscator

In this post I won’t go too much in depth about the internal de4dot architecture, mainly because I don’t know a whole lot about it. You’d have to check the built-in deobfuscators by yourself to find out how it works. Here is a post by kao that explains extending de4dot in a more detailed manner.

The identifying class for a deobfuscator is the DeobfuscatorInfo class. It has to provide a Name and a Type string field, where the Type field must be unique. It also has a CreateDeobfuscator method that will handle the actual deobfuscation.

You can find the full code over here. TheProxy wrote a full tutorial with details over at his blog

Sharing the deobfuscator

Now before I go into this, I have to say that you are obligated by the license de4dot uses (GPL) to share any modifications you make to de4dot under the same (GPL) license. This includes extensions that are dynamically loaded by de4dot, although this is controversial.

Now to share the deobfuscator, for example for internal company usage or simply because you want to share prebuilt binaries of your GPL extension, simply copy the bin/deobfuscator.OrangeHeap.dll to the de4dot bin directory on another machine. Here is a screenshot that shows what happens before and after I added the DLL to the bin directory (obviously without any other modifications to de4dot):


Overriding/Extending existing deobfuscators

If you want to change the behavior of an existing deobfuscator, simply make the DeobfuscatorInfo.Type field return an already-present typename (like co for CryptoDeobfuscator or df for Dotfuscator). Basically you have to rip the current deobfuscator class out in a separate project (I tested this). See here for a starting point. It should be pretty straightforward.

Well, that’s all for today. Hopefully till next time!

Mr. eXoDia

Leave a comment

Script Api

01 Jul 2015

Hey everyone,

For the people who keep checking this blog: thanks a lot!

Recently I had quite a lot of deadlines, so as usual I didn’t write anything on my blog :) I did however work on quite some interesting things. Together with the guys on #x64dbg and some other people I worked on a script API for x64dbg. What this means is that (once this API is finished) people can write bindings for their favorite script language and publish it as a plugin!

Right now I have these implemented:

  • Basic debugging stuff (run, step, stop, pause);
  • Register setters/getters;
  • Memory read/write;
  • Pattern finding/writing;
  • Module information;
  • GUI selection setters/getters.

I plan on adding much more:

  • PE information;
  • Breakpoint management;
  • Comment/Bookmark/Label/Function/Loop management (useful for analysis scripts);
  • Settings;
  • Event callbacks;
  • Etc (contact me if you have requests).

Some work was done with AngelScript in the testplugin.

void myStepOut()
    duint cip = Register::GetCIP();
    Print("[SCRIPT] Started on CIP = 0x%p\n", cip);
        cip = Register::GetCIP();
    while(Memory::ReadByte(cip) != 0xC3);
    Print("[SCRIPT] Finished on CIP = 0x%p\n", cip);

void main()
    Print("[SCRIPT] Welcome to AngelScript!\n");

Another idea I had was to load script DLLS, so you can write scripts in your favorite programming language (basically any language that supports native exports). You would write a single export StartScript that then calls the script API directly. This would allow for many possibilities, including commercial unpacking scripts.

This summer I will try to work on x64dbg as much as I can, to at least complete the script API. I also plan on fixing performance problems and solving as many issues as I can. Contact me if you know C++ and like to work on x64dbg. All help is appreciated.

Till next time,

Mr. eXoDia

Leave a comment

Function Analysis

11 May 2015

Hey everyone!

Right now I am in the fourth and final term of this education year. It looks like I can go on studying computer science, since I passed all my exams as of now!


In this post I will discuss a (fairly simple) algorithm I came up with half-drunk with the purpose of determining function boundaries in x86 assembly code. Right now, it is implemented in x64dbg and you can see how it works with a command called anal (short for analyze). It does not work on weird/obfuscated/Microsoft’s code, but it’s nice to have an idea where functions start and end without having to manually go through every function you are looking at.


x64dbg function

The requirements

Maybe you already noticed, but x64dbg does barely use the information provided in the PE Header of a debuggee for its operations. If your executable is malformed, but can be started by CreateProcess without problems x64dbg should be able to debug it.

The downside is that x64dbg has no idea if it is looking at code, an import table, a resource table or just random data. You would have to figure that out yourself. The upside is that anything that can be run by Windows can at least be started by x64dbg.

The algorithm has a very simple input: a block of memory. The output should be a list of function boundaries. It requires nothing to work, except the virtual base address of the memory block.

The idea

After talking with various people (including cyberbob who created ArkDasm) the thing a lot of people (including our ‘competition’ at HexRays) appear to do is some kind of recursive ‘tracing’ from a certain point (usually the entry point). Basically it simulates multiple possible execution paths from that point and constructs the function boundaries from data (such as call and ret instructions) it collected on the way.

Usually I like what the cool kids on the block do, but I saw some problems:

  1. Recursive algorithms require housekeeping. In this case you would need to make sure data is not analyzed more than once (in case of analyzing a recursive function).
  2. It is hard to estimate when the recursive algorithm would end. Maybe there is only one (very small) execution path and it ends immediately, or it keeps dragging on, evaluating thousands of possible paths.
  3. There is no known entry point.

Now computer scientists appear to like complexity analysis of an algorithm. Probably you cannot do better than linear anyway, so I decided that I wanted to algorithm to be done in linear time O(n).

The idea I had was very simple, but it requires two assumptions to work:

  1. Every call destination or immediate pointing inside the memory block given for analysis is assumed to be the start of a function;
  2. A function ends at or after the start of that function and cannot overlap with other functions.

The first assumption should be clear to you. The second assumption might not be, but it is actually very simple: when a function starts it has to end before another function starts. This means that this system will horribly break on optimized code that places chunks of code randomly scattered throughout the memory region. Microsoft’s kernel32.dll does this for example.

Now the actual idea is to do things in two steps:

  1. Find all function starts;
  2. Figure out where functions end.

Simple right?

Finding all function starts

Doing this is actually trivial with the given assumptions! Just find any immediate that points in the memory block currently being analyzed and then sort the results and remove duplicates (a function might be called from multiple places is why). The reason for the sorting that the end cannot be further away than the next function start.

Finding the end of a function #1

The thing that immediately comes to mind is just searching for the first ret instruction after the function start and call this the function end.

The problem with this approach is that there might be multiple exit points:

multiple exit points

Finding the end of a function #2

Another thing that comes in mind really quickly is just to scan backwards from a function start for the ret instruction. When found, this is the end of the previous function:

scan backwards

The main problem with this is that there could be unreferenced functions between the two functions that were found using the method for finding function starts. This could make really weird functions appear:

wrong functions

Finding the end of a function #3

The actual method I used to find the end of a function is a variation of #1. This algorithms has four cursors (the names are taken from the actual algorithm):

  1. addr is the current address being disassembled. addr will always move forward disassembling every instruction on the way;
  2. end is the current function end (basically this is the last ret instruction encountered by addr);
  3. fardest is the farthest forward destination of a jxx. This will point to the farthest destination the function can go by using jumps;
  4. jumpback is the address of the last jmp instruction that jumps before the end at that time.

For the understanding of the algorithm I visualized it using x64dbg. These are the colors used to indicate the various variables:

  • addr
  • end
  • fardest
  • jumpback

The first animation shows how fardest is used. When a ret instruction is encountered it is considered to be the function end if fardest has no value or points before the current ret instruction. When fardest points after the ret instruction, the algorithm will continue instead looking for another ret:

algorithm animation 1

The second animation shows how the jumpback variable is used. Basically what could happen is that there is some kind of repeated structure before a function returns and that the compiler optimized this by jumping back to this structure from the end of the function (this could be done to save space for example). When the limit to where the algorithm can disassemble is reached the jumpback will be used as end of the function instead of end:

algorithm animation 2

Final words

Alright, that was about it! I plan on improving this algorithm to support weird function structures done by some compilers, but the idea will stay the same (I think). I hope you enjoyed reading through this, I definitely enjoyed making it (even fixed some bugs on the way).


Mr. eXoDia

Leave a comment