<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Reverse Engineering on Kartone's Reversing Garage</title><link>https://blog.kartone.ninja/tags/reverse-engineering/</link><description>Recent content in Reverse Engineering on Kartone's Reversing Garage</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 16 Oct 2019 19:20:00 +0000</lastBuildDate><atom:link href="https://blog.kartone.ninja/tags/reverse-engineering/index.xml" rel="self" type="application/rss+xml"/><item><title>The p0sT5n1F3r Backdoor</title><link>https://blog.kartone.ninja/the-p0st5n1f3r-backdoor/</link><pubDate>Wed, 16 Oct 2019 19:20:00 +0000</pubDate><guid>https://blog.kartone.ninja/the-p0st5n1f3r-backdoor/</guid><description>&lt;img src="https://blog.kartone.ninja/images/2025/08/postsniffer.jpg" alt="Featured image of post The p0sT5n1F3r Backdoor" /&gt;&lt;p&gt;How does a malicious backdoor designed to sniff sensitive HTTPS traffic go completely undetected?&lt;/p&gt;
&lt;p&gt;During an IR case, we found and dissected a highly targeted malware sample, a custom Apache module we call&lt;code&gt;p0sT5n1F3r&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This threat was specifically engineered for its target&amp;rsquo;s environment and was rated 100% clean by all major security vendors due to its extensive use of custom encryption.&lt;/p&gt;
&lt;p&gt;This report details the reverse engineering journey, from the initial static analysis to the critical breakthrough: cracking its custom RC4 encryption scheme. This discovery allowed us to unveil its true purpose—intercepting financial transaction data—and even uncover a hidden HTML interface used by the attackers.&lt;/p&gt;
&lt;p&gt;Read the &lt;a class="link" href="https://blog.kartone.ninja/files/report.pdf" &gt;full technical deep dive&lt;/a&gt; to learn how this threat was unmasked.&lt;/p&gt;</description></item><item><title>WannaCry, two years later: a deep look into its code</title><link>https://blog.kartone.ninja/malware-analysis-a-wannacry-sample-found-in-the-wild-2/</link><pubDate>Thu, 23 May 2019 09:17:00 +0000</pubDate><guid>https://blog.kartone.ninja/malware-analysis-a-wannacry-sample-found-in-the-wild-2/</guid><description>&lt;img src="https://blog.kartone.ninja/images/2019/05/wannacry-screencap_thumb800-2.jpg" alt="Featured image of post WannaCry, two years later: a deep look into its code" /&gt;&lt;p&gt;My own technical analysis of the malware that, in 2017, spread like wildfire encrypting thousands of computers, using one of the tools leaked from the National Security Agency by the group named ShadowBrokers.&lt;/p&gt;
&lt;p&gt;Almost two years passed after that weekend of May 2017, when the crypto-worm WannaCry infested the net thanks to the EternalBlue exploit. In roughly two days, WannaCry spread itself all over the world infecting almost 230.000 computers in over 150 countries:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/Countries_initially_affected_in_WannaCry_ransomware_attack.svg"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;By TheAwesomeHwyh&lt;/p&gt;
&lt;p&gt;At that time, working as an Information Security Officer, with my colleagues, especially the guys from IT Infrastructure dept., worked hard to keep the entire Company perimeter safe. Luckily for us, we were not hit by the ransomware, but a lot of effort was spent explaining to the rest of the Company what happened.&lt;/p&gt;
&lt;h3 id="flash-forward-to-2019"&gt;Flash forward to 2019
&lt;/h3&gt;&lt;p&gt;Since this January, I&amp;rsquo;ve been running my own Dionaea honeypot that keeps catching a huge number of WannaCry samples. Just to give you some numbers, within two months, the 445 port was hit almost half a million times and I was able to collect roughly 18.000 of its samples at the rate of almost 300 samples per day.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image.png"
loading="lazy"
&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-1.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;If you notice from the file size, all these samples are all the same, and everyone of them is a WannaCry sample, delivered right to the 445 port in a DLL fashion.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-2.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Just to make a contribution to the WannaCry story, though small and useless, I thought it would be fun to analyze the internals of this malware as I wasn&amp;rsquo;t able to do it back in the days. I will concentrate the analysis on its various layers and the most important parts of the code that make this malware unique.&lt;/p&gt;
&lt;h2 id="peeling-the-onion"&gt;Peeling the onion
&lt;/h2&gt;&lt;p&gt;First look at one of these samples, confirms that we&amp;rsquo;re dealing with a malicious DLL and it&amp;rsquo;s worth to note its compilation timestamp. Let&amp;rsquo;s call this as &lt;code&gt;launcher.dll&lt;/code&gt; because of the evidence found in a string inside the code.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-3.png"
loading="lazy"
&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-12.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Luckily for us, this sample is not packed. We can check its &lt;strong&gt;Import and Export Address Table&lt;/strong&gt; to get an idea of what this sample is able to do.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-4.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Easily enough, checking the imported API, we can assume that the malware uses something in its &lt;strong&gt;resource&lt;/strong&gt; &lt;strong&gt;section&lt;/strong&gt; and supposedly create a file and run a process. Commonly, DLL malware exports functionalities to the outside via its &lt;strong&gt;Export Address Table&lt;/strong&gt;. We can see only one exported function and it&amp;rsquo;s called &lt;strong&gt;PlayGame&lt;/strong&gt;*:*&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-5.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;As noted above, malware imported some specific APIs to manage its resource section, like &lt;code&gt;FindResourceA&lt;/code&gt; and &lt;code&gt;LoadResource&lt;/code&gt;. We can easily recognize the &lt;em&gt;magic numbers&lt;/em&gt; of a Portable Executable file - a Windows executable file - stored inside this section. We can dump it easily with tools like ResourceHacker:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-6.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;But before analyzing it, we need to get rid of &lt;em&gt;some&lt;/em&gt; bytes in the header, we&amp;rsquo;ll come to these bytes later.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-7.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;So now, we can open it and check its sections like we just did with the aforementioned DLL. Interestingly this new dumped executable seems 7 years older than the first one, its compile timestamp is dated November 2010 but, be aware that this date can be easily fake.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-8.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can get an idea of what its purpose is by checking out the imported libraries:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-10.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We have to expect much more complexity in this stage than the DLL. We have a bunch of standard libraries like &lt;code&gt;KERNEL32.dll&lt;/code&gt; or &lt;code&gt;WININET.dll&lt;/code&gt; and &lt;code&gt;iphlpapi.dll&lt;/code&gt;. This DLL was unknown for me so I found, from &lt;a class="link" href="https://docs.microsoft.com/en-us/windows/desktop/iphlp/ip-helper-start-page" target="_blank" rel="noopener"
&gt;MSDN&lt;/a&gt;, that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Purpose&lt;/em&gt;&lt;br&gt;
The Internet Protocol Helper (IP Helper) API enables the retrieval and modification of network configuration settings for the local computer.&lt;br&gt;
The IP Helper API is applicable in any computing environment where programmatically manipulating network and TCP/IP configuration is useful. Typical applications include IP routing protocols and Simple Network Management Protocol (SNMP) agents.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-9.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;A quick look suggests that this executable operates with Windows services configuration, manages files and resources and also, has network capabilities:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-11.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h3 id="the-plan"&gt;The Plan
&lt;/h3&gt;&lt;p&gt;My plan is to give a deep look inside all various stages that the malware extracts during its execution, analyzing its code and how it interacts with internal Windows subsystems.&lt;/p&gt;
&lt;p&gt;For this reason, we&amp;rsquo;re now stepping back to analyze and understand how the DLL extracts this executable in the first place. Then we&amp;rsquo;ll give a look inside the debugger to see how things happen in realtime and then, we will analyze and try to understand what this executable is going to do once it infects the system.&lt;/p&gt;
&lt;h3 id="analysis-of-the-first-layer-launcherdll"&gt;Analysis of the first layer: launcher.dll
&lt;/h3&gt;&lt;p&gt;The purpose of this DLL is exactly what we supposed thanks to the analysis of the imported libraries. The only exported function &lt;code&gt;PlayGame&lt;/code&gt; is easily disassembled by IDAPro.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-13.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;The first call to &lt;code&gt;sprintf&lt;/code&gt; compose the &lt;code&gt;Dest&lt;/code&gt; string as &lt;code&gt;C:\WINDOWS\mssecsvc.exe&lt;/code&gt;. Then it calls two functions, &lt;code&gt;sub_10001016&lt;/code&gt; that extracts, from its resource section, the executable we dumped before and then, saves it into a new file named as &lt;code&gt;Dest&lt;/code&gt; string; after that &lt;code&gt;sub_100010AB&lt;/code&gt; runs the file. Notice that we have just gained our first &lt;strong&gt;host-based indicator&lt;/strong&gt;: &lt;strong&gt;&lt;code&gt;C:\WINDOWS\MSSECSVC.EXE&lt;/code&gt;&lt;/strong&gt; for this malware detection.&lt;/p&gt;
&lt;h4 id="function-sub_10001016-aka-extractandcreate"&gt;Function &lt;code&gt;sub_10001016&lt;/code&gt; aka &lt;code&gt;ExtractAndCreate&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;For better reading and understanding this function, we can rename it as &lt;code&gt;ExtractAndCreate&lt;/code&gt; and we can split it into two parts: the &lt;em&gt;extract&lt;/em&gt; part and the &lt;em&gt;create file&lt;/em&gt; part.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-14.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Disassembled extract part&lt;/p&gt;
&lt;p&gt;During this phase, the malware uses four API calls, that are completely covered inside the MSDN.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;FindResourceA&lt;/code&gt;: &lt;em&gt;Determines the location of a resource with the specified type and name in the specified module.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LoadResource&lt;/code&gt;: &lt;em&gt;Retrieves a handle that can be used to obtain a pointer to the first byte of the specified resource in memory.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LockResource&lt;/code&gt;: &lt;em&gt;Retrieves a pointer to the specified resource in memory.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SizeOfResource&lt;/code&gt;: &lt;em&gt;Retrieves the size, in bytes, of the specified resource.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That being said, we can now analyze step by step this simple four blocks of code. First function prototype is:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;HRSRC FindResourceA(
HMODULE hModule,
LPCSTR lpName,
LPCSTR lpType
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We have three function parameters that, as per calling convention, must be pushed in reverse order, so:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;push offset Type ; &amp;#34;W&amp;#34;
push 65h ; lpName
push hModule ; hModule
call ds:FindResourceA
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Parameter &lt;code&gt;hModule&lt;/code&gt; is being populated inside the &lt;code&gt;DLLMain&lt;/code&gt; method, and is equals to variable &lt;code&gt;hinstDLL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-15.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hinstDLL&lt;/code&gt;: &lt;em&gt;A handle to the DLL module. The value is the &lt;strong&gt;base address of the DLL&lt;/strong&gt;. The HINSTANCE of a DLL is the same as the HMODULE of the DLL, so hinstDLL can be used in calls to functions that require a module handle.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lpName&lt;/code&gt;: &lt;em&gt;The name of the resource.&lt;/em&gt; In this case, name is &lt;code&gt;0x65&lt;/code&gt; or &lt;code&gt;101&lt;/code&gt; in decimal value. If you look, name is confirmed by analyzing the DLL with ResourceHacker:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-16.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;lpType&lt;/code&gt;: &lt;em&gt;The resource type.&lt;/em&gt; Can be also noticed in the screenshot above.&lt;/p&gt;
&lt;p&gt;From &lt;a class="link" href="https://docs.microsoft.com/it-it/windows/desktop/api/winbase/nf-winbase-findresourcea" target="_blank" rel="noopener"
&gt;MSDN&lt;/a&gt;: &lt;em&gt;If the function succeeds, the return value is a handle to the specified resource&amp;rsquo;s information block. To obtain a handle to the resource, pass this handle to the &lt;code&gt;LoadResource&lt;/code&gt; function. If the function fails, the return value is &lt;code&gt;NULL&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Coming back to the disassembly, this handle is returned into &lt;code&gt;EAX&lt;/code&gt; and then moved inside &lt;code&gt;EDI&lt;/code&gt;, where is being tested to check if it&amp;rsquo;s &lt;code&gt;null&lt;/code&gt;. If it&amp;rsquo;s not, the handle is pushed, as the second argument, to the next API call to &lt;code&gt;LoadResource&lt;/code&gt;. Quoting &lt;a class="link" href="https://msdn.microsoft.com/en-us/library/ms648046%28v=VS.85%29.aspx" target="_blank" rel="noopener"
&gt;MSDN&lt;/a&gt;: &lt;em&gt;it&lt;/em&gt; &lt;em&gt;retrieves a handle that can be used to obtain a pointer to the first byte of the specified resource in memory.&lt;/em&gt; It also suggests:&amp;quot;&amp;hellip;&lt;em&gt;to obtain a pointer to the first byte of the resource data, call the &lt;a class="link" href="https://msdn.microsoft.com/en-us/library/ms648047%28v=vs.85%29.aspx" target="_blank" rel="noopener"
&gt;LockResource&lt;/a&gt; function; to obtain the size of the resource, call &lt;a class="link" href="https://msdn.microsoft.com/en-us/library/ms648048%28v=vs.85%29.aspx" target="_blank" rel="noopener"
&gt;SizeofResource&lt;/a&gt;&amp;quot;.&lt;/em&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;HGLOBAL WINAPI LoadResource(
_In_opt_ HMODULE hModule,
_In_ HRSRC hResInfo
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;hModule&lt;/code&gt;: &lt;em&gt;A handle to the module whose executable file contains the resource.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hResInfo&lt;/code&gt;: &lt;em&gt;A handle to the resource to be loaded.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The same approach applies with the other two API calls: &lt;code&gt;LockResource&lt;/code&gt; and &lt;code&gt;SizeofResource&lt;/code&gt;. The interesting thing to note here is that the return value from this last call, stored inside &lt;code&gt;EAX&lt;/code&gt; register as &lt;code&gt;500000&lt;/code&gt;, won&amp;rsquo;t be used at all:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/13.PNG"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;So now, looking in the debugger, we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;EAX&lt;/code&gt; = &lt;code&gt;500000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ESI&lt;/code&gt; = &lt;code&gt;10004060&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;ESI&lt;/code&gt; register contains the pointer to the memory region referred to the resource section that contains the executable itself. You can notice it thanks to the &lt;code&gt;MZ&lt;/code&gt; header in the memory dump. Remember the &lt;code&gt;4 bytes&lt;/code&gt; that were been removed with hex editor before? According to &lt;a class="link" href="https://docs.microsoft.com/en-us/windows/desktop/menurc/resource-file-formats" target="_blank" rel="noopener"
&gt;MSDN&lt;/a&gt; this DWORD is the actual size of raw data inside the resource section of the binary itself. So, this value &lt;code&gt;0x0038D000&lt;/code&gt;is moved into &lt;code&gt;EBX&lt;/code&gt; and then pushed as &lt;code&gt;lpBuffer&lt;/code&gt; to the &lt;code&gt;WriteFile&lt;/code&gt; function. Pretty standard call here: &lt;code&gt;CreateFileA&lt;/code&gt; will create a file with specific attributes. Parameter &lt;code&gt;dwFlagsAndAttributes&lt;/code&gt;, according to MSDN, a value of &lt;code&gt;0x4&lt;/code&gt;stands for: &lt;em&gt;&amp;ldquo;The file is part of or used exclusively by an operating system&amp;rdquo;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-17.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;After the call to &lt;code&gt;WriteFile&lt;/code&gt;, we have our executable saved and ready to run. The interesting parameters for this call are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lpBuffer&lt;/code&gt;: equals to &lt;code&gt;ESI&lt;/code&gt;, is the value returned by the call to &lt;code&gt;LockResource&lt;/code&gt; and is a pointer to the buffer to write into the file. Basically is a pointer to the binary inside the resource section.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nNumberOfBytesToWrite&lt;/code&gt;: as we said earlier, this parameter is the value pointed by the &lt;code&gt;ESI&lt;/code&gt; to a &lt;code&gt;DWORD&lt;/code&gt; inside of resource header. Its value represent the size of the binary data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So now, we can enable a breakpoint right after the &lt;code&gt;WriteFile&lt;/code&gt; call and get the freshly created executable.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/18.PNG"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h4 id="function-sub_100010ab-aka-runthefile"&gt;Function &lt;code&gt;sub_100010AB&lt;/code&gt; aka &lt;code&gt;RunTheFile&lt;/code&gt;
&lt;/h4&gt;&lt;p&gt;Here we&amp;rsquo;re dealing with a very simple API call to &lt;code&gt;CreateProcessA&lt;/code&gt;, nothing fancy to add. I&amp;rsquo;d prefer not to dig inside all these parameters, it&amp;rsquo;s completely covered inside the MSDN.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-20.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h4 id="conclusion-after-the-first-layer"&gt;Conclusion after the first layer
&lt;/h4&gt;&lt;p&gt;What I would show here is my own study process: be aware, sometimes it can be very, very time-consuming but it gives me a big, complete and deep look inside Windows internals and how malware uses them. This proceeding, for me as a novice, helped a lot.&lt;/p&gt;
&lt;h3 id="analysis-of-the-second-layer-mssecsvcexe"&gt;Analysis of the second layer: mssecsvc.exe
&lt;/h3&gt;&lt;p&gt;This will differs from the DLL file. As we noted initially, this executable is way more complex: we&amp;rsquo;ll deal with various libraries and functionalities. But all start with a (Win)main function, right?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-21.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Do you remember the kill-switch? Do you remember the &lt;a class="link" href="https://en.wikipedia.org/wiki/WannaCry_ransomware_attack" target="_blank" rel="noopener"
&gt;story&lt;/a&gt; behind? Give it a read, it&amp;rsquo;s very interesting.&lt;/p&gt;
&lt;p&gt;In general terms, the main function of a Windows program is named &lt;code&gt;WinMain&lt;/code&gt;, this is the first function that will be called when the program starts. We see a very strange url inside this code. Exactly the string is: &lt;code&gt;http://www.iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com&lt;/code&gt; and is referred through the &lt;code&gt;EDI&lt;/code&gt; register. After that, the &lt;code&gt;WinINet&lt;/code&gt; subsystem is initialized using the call to &lt;code&gt;InternetOpenA&lt;/code&gt;, this function &lt;em&gt;returns a valid handle that the application passes to subsequent WinINet functions.&lt;/em&gt; Next, there&amp;rsquo;s a call to &lt;code&gt;InternetOpenUrlA&lt;/code&gt; that &lt;em&gt;opens a resource specified by a complete FTP or HTTP URL.&lt;/em&gt; After that the handle is closed and a new function is called: &lt;code&gt;sub_408090&lt;/code&gt;, we&amp;rsquo;ll name it &lt;code&gt;ServiceStuff&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-22.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;In the first block of code, according to MSDN: &lt;code&gt;GetModuleFileNameA&lt;/code&gt; &lt;em&gt;retrieves the fully qualified path for the file that contains the specified module. The module must have been loaded by the current process, first parameter&lt;/em&gt; &lt;code&gt;hModule&lt;/code&gt; &lt;em&gt;is the handle to the loaded module whose path is being requested. If this parameter is &lt;strong&gt;NULL&lt;/strong&gt;,&lt;/em&gt; &lt;code&gt;GetModuleFileNameA&lt;/code&gt; &lt;em&gt;retrieves the path of the executable file of the current process.&lt;/em&gt; Here the value is set to &lt;code&gt;NULL&lt;/code&gt;, so it retrieves the name of the executable itself:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-23.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We then find a check on the number of arguments: if there are arguments the &lt;code&gt;TRUE&lt;/code&gt; path will be taken. Because, in our case, we&amp;rsquo;re debugging without any argument, the &lt;code&gt;FALSE&lt;/code&gt; path is taken and a new function &lt;code&gt;sub_407F20&lt;/code&gt; is called. This is a simple function that calls other two, so let&amp;rsquo;s call it &lt;code&gt;FunctionCaller&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-24.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Simple enough &lt;code&gt;sub_407C40&lt;/code&gt; create a new service and then starts it, so we name it &lt;code&gt;CreateAndStartService&lt;/code&gt;. Service will be run with command line &lt;code&gt;mssecsvc.exe -m security&lt;/code&gt; and with a display name as &lt;code&gt;&amp;quot;Microsoft Security Center (2.0) Service&amp;quot;&lt;/code&gt; defined as &lt;code&gt;&amp;quot;mssecsvc2.0&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-25.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;When we move then to &lt;code&gt;sub_407cE0&lt;/code&gt;, things start to become fun. For the sake of simplicity, we&amp;rsquo;ll analyze this function in four parts. The first part is easy because the malware dynamically resolve some APIs:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-26.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Nothing too much complicated here: it uses &lt;code&gt;GetProcAddress&lt;/code&gt; to populate some variables with the address of specific APIs, so it can call them in the next lines of code. After that, the second part will manage the resource section, just like the way we analyzed in the DLL &lt;code&gt;launcher.dll&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-27.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;This is confirmed into the debugger:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-28.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;The return value from &lt;code&gt;LockResource&lt;/code&gt;, as we know, is the pointer to the resource section into the binary and we can notice the &lt;code&gt;MZ&lt;/code&gt; header into the memory dump. We then reach another interesting piece of code:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-29.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Two distinct string: &lt;code&gt;Dest&lt;/code&gt; and &lt;code&gt;NewFileName&lt;/code&gt;, are created using &lt;code&gt;sprintf&lt;/code&gt; function. This two evidence are others good host-based indicators:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dest&lt;/code&gt; = &lt;code&gt;C:\WINDOWS\tasksche.exe&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NewFileName&lt;/code&gt; = &lt;code&gt;C:\WINDOWS\qeriuwjhrf&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;After that, the &lt;em&gt;old&lt;/em&gt; file &lt;code&gt;tasksche.exe&lt;/code&gt; is moved into the new file &lt;code&gt;qeriuwjhrf&lt;/code&gt; and a new &lt;code&gt;tasksche.exe&lt;/code&gt; is created. Now, I found myself lost into somehow obscure code: I got that &lt;code&gt;WriteFile&lt;/code&gt; will dump the &lt;strong&gt;R&lt;/strong&gt; resource into the created file &lt;code&gt;tasksche.exe&lt;/code&gt; and runs it at the end. What&amp;rsquo;s inside the middle part, for me, remains in the dark.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/Schermata-2019-05-17-alle-16.30.51.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;In situations like this, I prefer to view the code inside the debugger because viewing the code during runtime maybe can help to shed some light. Indeed, seems like It created the command line for the incoming &lt;code&gt;CreateProcessA&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-31.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;To recap: this function dumps its resource data inside a new executable file named &lt;code&gt;tasksche.exe&lt;/code&gt;, making a copy inside another file named &lt;code&gt;qeriuwjhrf&lt;/code&gt;, and then run &lt;code&gt;tasksche.exe /i&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Stepping back to &lt;code&gt;ServiceStuff&lt;/code&gt; function, there&amp;rsquo;s the other path to analyze: when there are the arguments &lt;code&gt;&amp;quot;-m security&amp;quot;&lt;/code&gt;, it enters into service mode. After its initialization, it changes service config:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-32.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;According to &lt;a class="link" href="https://docs.microsoft.com/en-us/windows/desktop/api/winsvc/nf-winsvc-changeserviceconfig2a" target="_blank" rel="noopener"
&gt;MSDN&lt;/a&gt;, &lt;em&gt;it changes the config so that failure actions occur if the service exits without entering a SERVICE_STOPPED state&lt;/em&gt;. After that, it executes its &lt;code&gt;ServiceFunction&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-33.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;This function setup the handles and starts exploiting the &lt;code&gt;MS17-010&lt;/code&gt; vulnerability into the reachable networks. Note that it exits after 24h. Here, I renamed this function &lt;code&gt;ExecuteEternalBlue&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-34.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;This call starts a number of events that let the infection to happen. First thing, Winsock subsystem is initialized and a CryptoContext is generated:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-35.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Next, the malware will load a DLL into the memory - the very same &lt;code&gt;launcher.dll&lt;/code&gt; we analyzed before - and then run it. Networks attacks happen inside two new threads. This flow can be easily observed if we decompile this function:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-36.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;The first thread, involving the function &lt;code&gt;sub_407720&lt;/code&gt;, will enumerates local network adapters and generates IP addresses compatible for those networks. For every IP, it tries to connect to port 445 and, if successful, launch the attack. Second thread, involving function &lt;code&gt;sub_407840&lt;/code&gt;, will run 128 times with 2 seconds (hex &lt;code&gt;7D0&lt;/code&gt;) delay between each run. It will generates random IP address and tries to connect on port 445, if connection is successful, malware will launch the EternalBlue attack. It&amp;rsquo;s a pretty big chunk of code, but one interesting block of code is this:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-37.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Basically the malware, with the random IP placed into the &lt;code&gt;Dest&lt;/code&gt; string converted into the proper format, calls &lt;code&gt;sub_407480&lt;/code&gt; aka &lt;code&gt;CreateSocketAndConnect&lt;/code&gt; to try a connection to the 445 port, if the connection is successful, real attack is launched within the function &lt;code&gt;sub_407540&lt;/code&gt; aka &lt;code&gt;SMBAttack&lt;/code&gt;.&lt;/p&gt;
&lt;h4 id="conclusion-after-the-second-layer"&gt;Conclusion after the second layer
&lt;/h4&gt;&lt;p&gt;So, until now, we got a DLL - &lt;code&gt;launcher.dll&lt;/code&gt; - that loads and runs a binary stored inside its resource section,&lt;code&gt;mssecsvc.exe&lt;/code&gt;. The very first time, a new service is created to achieve persistence and after that it scans the networks (local and random remote) launching the EternalBlue exploits against 445 ports. In its stand-alone version, it dumps another binary from its resource section and runs it. What&amp;rsquo;s the purpose of this third binary? Let&amp;rsquo;s give a look.&lt;/p&gt;
&lt;h3 id="analysis-of-the-third-layer-taskscheexe"&gt;Analysis of the third layer: tasksche.exe
&lt;/h3&gt;&lt;p&gt;Remember that this executable come from the resource section of previous file, &lt;code&gt;mssecsvc.exe&lt;/code&gt;. When it runs as service, locates its resource section and writes it to the disk creating &lt;code&gt;tasksche.exe&lt;/code&gt;. When it starts, it first generates a random string based on computer name, then checks if there are some command line arguments, in particular, if there&amp;rsquo;s &lt;code&gt;/i&lt;/code&gt; as argument. We have now two branches to analyze:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If there&amp;rsquo;s &lt;code&gt;/i&lt;/code&gt; argument: it creates specific directories and copies the file over it, like &lt;code&gt;C:\ProgramData\somerandomstring\tasksche.exe&lt;/code&gt; and runs it from there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-39.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If there&amp;rsquo;s no &lt;code&gt;/i&lt;/code&gt; argument: it locates its resource section, named &lt;strong&gt;XIA&lt;/strong&gt;, storing and extracting it onto disk. What&amp;rsquo;s interesting to note here that this resource is a compressed &lt;em&gt;password protected&lt;/em&gt; archive. Luckily for us, password is hardcoded in clear text.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-40.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s give a look inside the archive knowing the password: &lt;strong&gt;WNcry@2ol7&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-41.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can recognize the magic numbers for a ZIP file that we can dump directly and extract.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-43.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;b.wnry&lt;/code&gt; is the bitmap image of the ransomware. Basically what you see as wallpaper when the computer is infected.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-44.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;c.wnry&lt;/code&gt; is the configuration file in clear text, we can see some &lt;code&gt;onion&lt;/code&gt; servers and the archive containing the TOR browser.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-45.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;r.wnry&lt;/code&gt; contains some text ransom note.&lt;/p&gt;
&lt;p&gt;Inside the &lt;code&gt;msg&lt;/code&gt; folder there are some localized ransom note:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/05/image-46.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h4 id="conclusion-after-the-third-layer"&gt;Conclusion after the third layer
&lt;/h4&gt;&lt;p&gt;This new executable seems pretty interesting because basically, it manages all the crypto actions involved within the ransomware. I won&amp;rsquo;t go into this analysis because it&amp;rsquo;s beyond my actual skills and also because, there are plenty of resources available on the internet, from amazing guys that are way better than me. For example, &lt;a class="link" href="https://www.fireeye.com/blog/threat-research/2017/05/wannacry-malware-profile.html" target="_blank" rel="noopener"
&gt;this&lt;/a&gt; technical analysis by FireEye was published only few days aftermath and is complete, deep and detailed. I used it a lot to better understand many pieces of obscure code.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;I have learned a lot from this research: I learned how malware interacts with their resource section to hide, dump and create files; I learned how malware interacts with Windows service manager and how they actually load DLLs in memory, how they scans networks and how EternalBlue actually works. Also, having available such complete and detailed technical analysis, on this very specific malware, helped me to not loose the direction when I went too deep inside the assembly code. It was very fun and I hope this research will be helpful to someone at least as it was for me.&lt;/p&gt;</description></item><item><title>An extensive step by step reverse engineering analysis of a Linux CTF binary</title><link>https://blog.kartone.ninja/when-a-reverse-me-ctf-binary-makes-you-loose-that-job/</link><pubDate>Mon, 25 Mar 2019 09:00:00 +0000</pubDate><guid>https://blog.kartone.ninja/when-a-reverse-me-ctf-binary-makes-you-loose-that-job/</guid><description>&lt;img src="https://blog.kartone.ninja/images/2019/03/sshot.png" alt="Featured image of post An extensive step by step reverse engineering analysis of a Linux CTF binary" /&gt;&lt;p&gt;&amp;hellip;or, in other words, &lt;em&gt;when failing to reverse a CTF binary makes you lose that job&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;During a past job interview, I was tasked to reverse four linux binaries of increasing difficulties as proof of my ability into the reverse engineering field. I solved the first two in a matter of an hour, the third one required me an entire day of work but sadly, I was not able to solve the last one. I don&amp;rsquo;t know if I wasn&amp;rsquo;t selected because of this fail, but it proved me one sure thing: I wasn&amp;rsquo;t prepared enough or, at least, as much as I wanted. Flash forward, I successfully ended up with another job, but that challenge kept staying there, like a small needle, in my head. During the following months, I studied and practiced a lot, mainly into firmware reversing field and, every now and then, I&amp;rsquo;ve tried to solve that sneaky challenge.&lt;/p&gt;
&lt;p&gt;This is my extensive and detailed description of my fails and success.&lt;/p&gt;
&lt;h4 id="important-note"&gt;Important note
&lt;/h4&gt;&lt;p&gt;Please note that as this analysis started some months ago and this post was reviewed a huge number of times, you won&amp;rsquo;t find same memory addresses or function names across the screenshots and code snippets.&lt;/p&gt;
&lt;h2 id="running-the-binary"&gt;Running the binary
&lt;/h2&gt;&lt;p&gt;With what are we dealing?&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:/opt/ctf# file original
original: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=d0d5b9a34a4fe4c52a3939c75bd71cfa0dc23825, stripped
root@kali:/opt/ctf# checksec -f ./original
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols No 0 2 ./original
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A standard, stripped, Linux 32bit binary with no fancy protection active. We&amp;rsquo;re not aiming to exploit it but only to find the flag. A picture is worth a thousand words, they say:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:/opt/ctf# ./original
[-] No vm please ;)
root@kali:/opt/ctf# ./original AAAA
[-] No vm please ;)
root@kali:/opt/ctf# ./original -h
[-] No vm please ;)
root@kali:/opt/ctf# ./original AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[-] No vm please ;)
root@kali:/opt/ctf#
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It doesn&amp;rsquo;t run inside a virtual machine and I definitely don&amp;rsquo;t want to build a physical linux box. Would you tell me some of your internals, please?&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:/opt/ctf# strace ./original
execve(&amp;#34;./original&amp;#34;, [&amp;#34;./original&amp;#34;], 0x7fff2a7dc4f0 /* 48 vars */) = 0
strace: [ Process PID=121645 runs in 32 bit mode. ]
brk(NULL) = 0x572fb000
access(&amp;#34;/etc/ld.so.nohwcap&amp;#34;, F_OK) = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xf7f05000
access(&amp;#34;/etc/ld.so.preload&amp;#34;, R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, &amp;#34;/etc/ld.so.cache&amp;#34;, O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=133840, ...}) = 0
mmap2(NULL, 133840, PROT_READ, MAP_PRIVATE, 3, 0) = 0xf7ee4000
close(3) = 0
access(&amp;#34;/etc/ld.so.nohwcap&amp;#34;, F_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, &amp;#34;/lib/i386-linux-gnu/libc.so.6&amp;#34;, O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 3
read(3, &amp;#34;\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\254\1\0004\0\0\0&amp;#34;..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1947056, ...}) = 0
mmap2(NULL, 1955712, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xf7d06000
mprotect(0xf7d1f000, 1830912, PROT_NONE) = 0
mmap2(0xf7d1f000, 1368064, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19000) = 0xf7d1f000
mmap2(0xf7e6d000, 458752, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x167000) = 0xf7e6d000
mmap2(0xf7ede000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d7000) = 0xf7ede000
mmap2(0xf7ee1000, 10112, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xf7ee1000
close(3) = 0
set_thread_area({entry_number=-1, base_addr=0xf7f060c0, limit=0x0fffff, seg_32bit=1, contents=0, read_exec_only=0, limit_in_pages=1, seg_not_present=0, useable=1}) = 0 (entry_number=12)
mprotect(0xf7ede000, 8192, PROT_READ) = 0
mprotect(0x565b8000, 4096, PROT_READ) = 0
mprotect(0xf7f34000, 4096, PROT_READ) = 0
munmap(0xf7ee4000, 133840) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0xf7f06128) = 121646
waitpid(121646, [{WIFEXITED(s) &amp;amp;&amp;amp; WEXITSTATUS(s) == 1}], 0) = 121646
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=121646, si_uid=0, si_status=1, si_utime=0, si_stime=0} ---
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x1), ...}) = 0
brk(NULL) = 0x572fb000
brk(0x5731c000) = 0x5731c000
brk(0x5731d000) = 0x5731d000
write(1, &amp;#34;**[-] You fool, nobody debugs me!!**&amp;#34;..., 34[-] You fool, nobody debugs me!!!
) = 34
write(1, &amp;#34;1\n&amp;#34;, 21
) = 2
exit_group(-1) = ?
+++ exited with 255 +++
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;You fool, nobody debugs me!!!&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Great, after a few couples of runs, we know that there are some anti-VM and anti-debug code in place. Let&amp;rsquo;s look inside.&lt;/p&gt;
&lt;p&gt;First thing, I searched and found the strings pretty quickly, and I noticed also two other interesting strings: one for a fail, one for a success.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-12-alle-23.01.47.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Digging a little more, we can find where are placed the strings and from where they&amp;rsquo;re used for.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-12-alle-23.08.08.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s clear that the subroutine placed at address &lt;code&gt;0x566429DC&lt;/code&gt; has something to do with them and with the anti-VM/anti-debug tricks.&lt;/p&gt;
&lt;h2 id="analyzing-the-anti-debug-and-anti-vm-routine"&gt;Analyzing the anti-debug and anti-vm routine
&lt;/h2&gt;&lt;p&gt;Once I have identified where are the strings involved in this anti-debug and anti-vm tricks, it&amp;rsquo;s easy to find them and visualize the blocks in IDA. Please note that &lt;code&gt;sub_566429DC&lt;/code&gt; was here renamed in &lt;code&gt;AntiDebugAntiVM&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/graph.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;This is the graph of the AntiDebugAntiVM functions. In the first block of code, we can see the standard function call convention that setup the stack frame. After that, a bunch of  &lt;code&gt;NOPS&lt;/code&gt; and a call to &lt;code&gt;fork()&lt;/code&gt;. Let&amp;rsquo;s understand the fork call, what&amp;rsquo;s its purpose?&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;fork()&lt;/strong&gt; creates a new process by duplicating the calling process. The new process, referred to as the &lt;strong&gt;child&lt;/strong&gt;, is an exact duplicate of the calling process, referred to as the &lt;strong&gt;parent&lt;/strong&gt;. &lt;em&gt;On success, the PID of the child process is returned in the parent, and 0 is returned in the child&lt;/em&gt;. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately. (&lt;a class="link" href="http://man7.org/linux/man-pages/man2/fork.2.html" target="_blank" rel="noopener"
&gt;ref&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Basically, right after the fork call, its return value is saved into the &lt;code&gt;EAX&lt;/code&gt; register and then moved into a local variable that is compared with the zero value. The first branch is important: if the &lt;code&gt;JNZ&lt;/code&gt; is true, we&amp;rsquo;re into the parent process so we&amp;rsquo;re going into the right path. Vice versa, if the instruction is false we&amp;rsquo;re heading to the left or into the child process.&lt;/p&gt;
&lt;h3 id="into-the-child-process"&gt;Into the child process
&lt;/h3&gt;&lt;p&gt;If &lt;code&gt;EAX&lt;/code&gt; is zero, or in other terms, we&amp;rsquo;re into the child process, we can see a call to &lt;code&gt;getppid()&lt;/code&gt;function that &lt;a class="link" href="http://man7.org/linux/man-pages/man2/getpid.2.html" target="_blank" rel="noopener"
&gt;returns the process ID of the parent of the calling process&lt;/a&gt;.  But the important call is the next one, the call to the &lt;code&gt;ptrace()&lt;/code&gt; function. The standard definition of this function is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;strong&gt;ptrace&lt;/strong&gt;() system call provides a means by which one process (the&amp;quot;tracer&amp;quot;) may observe and control the execution of another process(the &amp;ldquo;tracee&amp;rdquo;), and examine and change the tracee&amp;rsquo;s memory and registers. It is primarily used to implement breakpoint debugging and system call tracing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And is defined as:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In assembly, the call is built with these lines of code:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;push 0 ; *data
push 0 ; *addr
push [ebp+var_1C] ; Parent PID
push 10h ; _ptrace_request
call _ptrace
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically, the child retrieve its PPID and tries to &lt;em&gt;attach a debugger&lt;/em&gt; [1]&lt;em&gt;,&lt;/em&gt; if it fails, it&amp;rsquo;s the evidence that it is being debugged so sleep 5 seconds, detach and returns [2] . Otherwise returns anyway [3]. Going up a level, if the &lt;code&gt;fork()&lt;/code&gt; return &lt;code&gt;-1&lt;/code&gt; so returns with the status code &lt;code&gt;1&lt;/code&gt; [5]&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-14-alle-20.48.53.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h3 id="into-the-parent-process"&gt;Into the parent process
&lt;/h3&gt;&lt;p&gt;If &lt;code&gt;EAX&lt;/code&gt; is not zero, we&amp;rsquo;re in the right path, so in the parent process. As you can remember, we have the PID of the child into the &lt;code&gt;EAX&lt;/code&gt; register. After the check with &lt;code&gt;-1&lt;/code&gt; into the block [1], it goes into the block [2]. Here, the parent performs a call to &lt;code&gt;waitpid()&lt;/code&gt;:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;push 0 ; options
lea eax, [ebp+stat_loc]
push eax ; stat_loc
push [ebp+pid] ; child PID
call _waitpid
&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;waitpid()&lt;/code&gt; system call is used to wait for state changes in a child of the calling process, and obtain information about the child whose state has changed. A state change is considered to be: the child terminated; the child was stopped by a signal; or the child was resumed by a signal. In the case of a terminated child, performing a wait allows the system to release the resources associated with the child; if a wait is not performed, then the terminated child remains in a &amp;ldquo;zombie&amp;rdquo; state. (&lt;a class="link" href="http://man7.org/linux/man-pages/man2/wait.2.html" target="_blank" rel="noopener"
&gt;ref&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-14-alle-21.05.54.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;On success, &lt;code&gt;waitpid()&lt;/code&gt; returns the process ID of the child whose state has changed; On error, &lt;code&gt;-1&lt;/code&gt; is returned. In the next blocks 2, 3, 4 and 5 what happens is described in this answer I got on &lt;a class="link" href="https://reverseengineering.stackexchange.com/questions/20808/fork-and-waitpid-calls-in-a-ctf-linux-binary/20818?noredirect=1#comment33616_20818" target="_blank" rel="noopener"
&gt;ReverseEngineering&lt;/a&gt;. There&amp;rsquo;s no need to add anything more.&lt;/p&gt;
&lt;h3 id="anti-vm-code"&gt;Anti-VM code
&lt;/h3&gt;&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/image-3.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;This is where things become fun and interesting. We can observe a bunch of &lt;code&gt;mov&lt;/code&gt; instructions into the stack, a loop and inside of it an interesting &lt;code&gt;xor&lt;/code&gt; instruction: &lt;code&gt;xor eax, 75h&lt;/code&gt;. It seems to be a loop that cycle &lt;code&gt;0x32&lt;/code&gt; times (&lt;code&gt;50&lt;/code&gt;in decimal) and starting from &lt;code&gt;[ebp+command]&lt;/code&gt; it &lt;em&gt;xors&lt;/em&gt; one byte at a time to a fixed value equal to &lt;code&gt;\x75&lt;/code&gt;. Pretty standard XOR decryption routine, right? We can try to replicate this routine in python:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#!/usr/bin/python
hexdata = &amp;#34;19061605005509551207100555523D0C051007031C061A07525509550107555811555255525509551600015558114F55581347&amp;#34;
binary = hexdata.decode(&amp;#34;hex&amp;#34;)
def xor_strings(data):
return &amp;#34;&amp;#34;.join(chr(ord(data[i]) ^ 0x75) for i in range(len(data)))
xored = xor_strings(binary)
print &amp;#34;Your decrypted string is: &amp;#34; + xored
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:/opt/ctf# ./script.py
Your decrypted string is: lscpu | grep &amp;#39;Hypervisor&amp;#39; | tr -d &amp;#39; &amp;#39; | cut -d: -f2
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically, it decrypts &lt;em&gt;in memory&lt;/em&gt; a shell command and execute it via the next &lt;code&gt;popen&lt;/code&gt; syscall that verifies, using the &lt;code&gt;lscpu&lt;/code&gt; command, if the CPU name contains a string &lt;code&gt;Hypervisor&lt;/code&gt;. This syscall looks pretty interesting:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The  &lt;code&gt;popen()&lt;/code&gt; function opens a process by creating a pipe, forking, and invoking the shell. Since a pipe is by definition unidirectional, the type argument may specify only reading or writing, not both; the resulting stream is correspondingly read-only or write-only. The command argument is a pointer to a null-terminated string containing a shell command line.  This command is passed to /bin/sh using the -c flag; interpretation, if any, is performed by the shell. The type argument is a pointer to a null-terminated string which must contain either the letter &amp;lsquo;r&amp;rsquo; for reading or the letter &amp;lsquo;w&amp;rsquo; for writing. &lt;code&gt;popen()&lt;/code&gt;: on success, returns a pointer to an open stream that can be used to read or write to the pipe; if the &lt;a class="link" href="http://man7.org/linux/man-pages/man2/fork.2.html" target="_blank" rel="noopener"
&gt;fork(2)&lt;/a&gt; or &lt;a class="link" href="http://man7.org/linux/man-pages/man2/pipe.2.html" target="_blank" rel="noopener"
&gt;pipe(2)&lt;/a&gt; calls fail, or if the function cannot allocate memory, &lt;code&gt;NULL&lt;/code&gt; is returned.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;After the stream is opened, another syscall &lt;code&gt;fgetc()&lt;/code&gt; is executed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;fgetc()&lt;/code&gt; reads the next character from &lt;em&gt;stream&lt;/em&gt; and returns it as an        &lt;em&gt;unsigned char&lt;/em&gt; cast to an &lt;em&gt;int&lt;/em&gt;, or EOF on end of file or error.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What happens is simple: it opens a stream, in read-only mode, and executes the command &lt;code&gt;'lscpu | grep 'Hypervisor' | tr -d ' ' | cut -d: -f2'&lt;/code&gt; . If it returns something, so the &lt;code&gt;grep&lt;/code&gt; returns something, we&amp;rsquo;re in a virtual machine, prints the string: &lt;code&gt;[-] No vm please ;)&lt;/code&gt; and exit. If the stream fails or it does not return anything, it closes the stream via the &lt;code&gt;fclose()&lt;/code&gt; syscall and returns.&lt;/p&gt;
&lt;p&gt;Everything becomes clear if we look now into the pseudo-code, with important variables renamed as their role.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int AntiDebugAntiVM()
{
char command; // [esp+4h] [ebp-54h]
char v2; // [esp+5h] [ebp-53h]
char v3; // [esp+6h] [ebp-52h]
char v4; // [esp+7h] [ebp-51h]
char v5; // [esp+8h] [ebp-50h]
char v6; // [esp+9h] [ebp-4Fh]
char v7; // [esp+Ah] [ebp-4Eh]
char v8; // [esp+Bh] [ebp-4Dh]
char v9; // [esp+Ch] [ebp-4Ch]
char v10; // [esp+Dh] [ebp-4Bh]
char v11; // [esp+Eh] [ebp-4Ah]
char v12; // [esp+Fh] [ebp-49h]
char v13; // [esp+10h] [ebp-48h]
char v14; // [esp+11h] [ebp-47h]
char v15; // [esp+12h] [ebp-46h]
char v16; // [esp+13h] [ebp-45h]
char v17; // [esp+14h] [ebp-44h]
char v18; // [esp+15h] [ebp-43h]
char v19; // [esp+16h] [ebp-42h]
char v20; // [esp+17h] [ebp-41h]
char v21; // [esp+18h] [ebp-40h]
char v22; // [esp+19h] [ebp-3Fh]
char v23; // [esp+1Ah] [ebp-3Eh]
char v24; // [esp+1Bh] [ebp-3Dh]
char v25; // [esp+1Ch] [ebp-3Ch]
char v26; // [esp+1Dh] [ebp-3Bh]
char v27; // [esp+1Eh] [ebp-3Ah]
char v28; // [esp+1Fh] [ebp-39h]
char v29; // [esp+20h] [ebp-38h]
char v30; // [esp+21h] [ebp-37h]
char v31; // [esp+22h] [ebp-36h]
char v32; // [esp+23h] [ebp-35h]
char v33; // [esp+24h] [ebp-34h]
char v34; // [esp+25h] [ebp-33h]
char v35; // [esp+26h] [ebp-32h]
char v36; // [esp+27h] [ebp-31h]
char v37; // [esp+28h] [ebp-30h]
char v38; // [esp+29h] [ebp-2Fh]
char v39; // [esp+2Ah] [ebp-2Eh]
char v40; // [esp+2Bh] [ebp-2Dh]
char v41; // [esp+2Ch] [ebp-2Ch]
char v42; // [esp+2Dh] [ebp-2Bh]
char v43; // [esp+2Eh] [ebp-2Ah]
char v44; // [esp+2Fh] [ebp-29h]
char v45; // [esp+30h] [ebp-28h]
char v46; // [esp+31h] [ebp-27h]
char v47; // [esp+32h] [ebp-26h]
char v48; // [esp+33h] [ebp-25h]
char v49; // [esp+34h] [ebp-24h]
char v50; // [esp+35h] [ebp-23h]
char v51; // [esp+36h] [ebp-22h]
char v52; // [esp+37h] [ebp-21h]
int stat_loc; // [esp+38h] [ebp-20h]
__pid_t ParentPID; // [esp+3Ch] [ebp-1Ch]
FILE *stream; // [esp+40h] [ebp-18h]
__pid_t ChangedStateChildPID; // [esp+44h] [ebp-14h]
__pid_t ChildPID; // [esp+48h] [ebp-10h]
unsigned int i; // [esp+4Ch] [ebp-Ch]
ChildPID = fork();
if ( !ChildPID )
{
ParentPID = getppid();
if ( ptrace(PTRACE_ATTACH, ParentPID, 0, 0) )
{
stat_loc = 1;
exit(1);
}
sleep(5u);
ptrace(PTRACE_DETACH, ParentPID, 0, 0);
exit(0);
}
if ( ChildPID == -1 )
exit(1);
do
ChangedStateChildPID = waitpid(ChildPID, &amp;amp;stat_loc, 0);
while ( ChangedStateChildPID == -1 &amp;amp;&amp;amp; *__errno_location() == 4 );
if ( BYTE1(stat_loc) )
{
printf(&amp;#34;[-] You fool, nobody debugs me!!!\n%d\n&amp;#34;, BYTE1(stat_loc));
exit(-1);
}
command = 0x19;
v2 = 6;
v3 = 0x16;
v4 = 5;
v5 = 0;
v6 = 0x55;
v7 = 9;
v8 = 0x55;
v9 = 0x12;
v10 = 7;
v11 = 0x10;
v12 = 5;
v13 = 0x55;
v14 = 0x52;
v15 = 0x3D;
v16 = 0xC;
v17 = 5;
v18 = 0x10;
v19 = 7;
v20 = 3;
v21 = 0x1C;
v22 = 6;
v23 = 0x1A;
v24 = 7;
v25 = 0x52;
v26 = 0x55;
v27 = 9;
v28 = 0x55;
v29 = 1;
v30 = 7;
v31 = 0x55;
v32 = 0x58;
v33 = 0x11;
v34 = 0x55;
v35 = 0x52;
v36 = 0x55;
v37 = 0x52;
v38 = 0x55;
v39 = 9;
v40 = 0x55;
v41 = 0x16;
v42 = 0;
v43 = 1;
v44 = 0x55;
v45 = 0x58;
v46 = 0x11;
v47 = 0x4F;
v48 = 0x55;
v49 = 0x58;
v50 = 0x13;
v51 = 0x47;
v52 = 0;
for ( i = 0; i &amp;lt;= 50; ++i )
*(&amp;amp;command + i) ^= 0x75u;
stream = popen(&amp;amp;command, &amp;#34;r&amp;#34;);
if ( stream &amp;amp;&amp;amp; fgetc(stream) != -1 )
{
puts(&amp;#34;[-] No vm please ;)&amp;#34;);
exit(-1);
}
return fclose(stream);
}
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="first-round-of-conclusions"&gt;First round of conclusions
&lt;/h2&gt;&lt;p&gt;Right now it may seem pretty easy, but for me at that time, this was impossible to understand and represented the first big fail: I was not prepared with interpreting assembly XOR instruction, decryption loops and Linux syscalls. I spent almost an entire weekend on this and failed so hard. Because of the time constraints of the job selection, I sent my results without this last exercise and &lt;em&gt;maybe&lt;/em&gt; this influenced my performance into the selection. How to bypass all these checks? We need to find from where this function is called and maybe we could modify the code flow to avoid this calling.&lt;/p&gt;
&lt;h2 id="jumping-away"&gt;Jumping away
&lt;/h2&gt;&lt;p&gt;With the IDA basic functionalities, we can find where this function is called and, luckily for us, it&amp;rsquo;s called from a single location:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/image-4.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;The instruction that calls the function is located inside this &lt;code&gt;sub_E00&lt;/code&gt; and, in particular, IDA shows that&amp;rsquo;s the instruction: &lt;code&gt;call ds:(off_2EF0-3000h) [ebx+edi*4]&lt;/code&gt;. Looking around this code we can patch the &lt;code&gt;jz short loc_E55&lt;/code&gt; into a &lt;code&gt;jmp&lt;/code&gt;, so we would be able to circumvent all of the above protections.&lt;/p&gt;
&lt;h3 id="cheating-with-the-shell"&gt;Cheating with the shell
&lt;/h3&gt;&lt;p&gt;If you don&amp;rsquo;t want to patch the binary, there&amp;rsquo;s another way to fool this VM check, but &lt;strong&gt;not&lt;/strong&gt; the anti-debug. If you notice, the command passed as an argument to the &lt;code&gt;popen&lt;/code&gt; syscall is a normal shell command but with a &lt;em&gt;relative path&lt;/em&gt;. So quick and dirty trick would be to create a fake &lt;code&gt;lscpu&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;#!/bin/bash
echo &amp;#34;I will run you anyway in this VM&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Be sure to export the directory inside the PATH variable and, basically, you&amp;rsquo;re done: when the binary will try to execute the &lt;code&gt;lscpu&lt;/code&gt; command, it will run the fake one, it won&amp;rsquo;t return anything containing &lt;em&gt;Hypervisor&lt;/em&gt; string, the &lt;code&gt;grep&lt;/code&gt; would return nothing and the &lt;code&gt;fgetc&lt;/code&gt; consequently will read nothing. Basically, all checks are positive. Easy as it seems.&lt;/p&gt;
&lt;h2 id="analyzing-the-self-decrypting-and-injecting-routine"&gt;Analyzing the self decrypting and injecting routine
&lt;/h2&gt;&lt;p&gt;We can take advantages of the debugging capabilities of IDA and playing with breakpoints. Single stepping into the program flow, after the above routines, we land into this interesting piece of code:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/image-5.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;I spent &lt;em&gt;a lot&lt;/em&gt; of days trying to understand this routine: but it was worth it because I learned &lt;strong&gt;a lot&lt;/strong&gt;: I learned about linux syscalls like &lt;code&gt;mprotect&lt;/code&gt;, &lt;code&gt;calloc&lt;/code&gt; and also &lt;code&gt;memcpy&lt;/code&gt;. I learned about how the code could auto-decrypt and auto-inject inside the binary itself. Moreover, how can be possible to change memory protections back and forth. Indeed, it was very helpful to look around this code, side by side, with its decompiled version:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int sub_CB5()
{
char v0; // si
size_t v1; // eax
char s; // [esp+8h] [ebp-30h]
char v4; // [esp+9h] [ebp-2Fh]
char v5; // [esp+Ah] [ebp-2Eh]
char v6; // [esp+Bh] [ebp-2Dh]
char v7; // [esp+Ch] [ebp-2Ch]
char v8; // [esp+Dh] [ebp-2Bh]
char v9; // [esp+Eh] [ebp-2Ah]
char v10; // [esp+Fh] [ebp-29h]
char v11; // [esp+10h] [ebp-28h]
char v12; // [esp+11h] [ebp-27h]
char v13; // [esp+12h] [ebp-26h]
char v14; // [esp+13h] [ebp-25h]
char v15; // [esp+14h] [ebp-24h]
char v16; // [esp+15h] [ebp-23h]
char v17; // [esp+16h] [ebp-22h]
char v18; // [esp+17h] [ebp-21h]
char v19; // [esp+18h] [ebp-20h]
char v20; // [esp+19h] [ebp-1Fh]
char v21; // [esp+1Ah] [ebp-1Eh]
char v22; // [esp+1Bh] [ebp-1Dh]
void *src; // [esp+1Ch] [ebp-1Ch]
_BYTE *v24; // [esp+20h] [ebp-18h]
void *addr; // [esp+24h] [ebp-14h]
size_t n; // [esp+28h] [ebp-10h]
size_t i; // [esp+2Ch] [ebp-Ch]
n = 320;
addr = 0;
v24 = &amp;amp;unk_E78;
mprotect(0, (size_t)((char *)&amp;amp;unk_E78 - 0xFFFFD000 - 12288), 6);
s = 0xF9u;
v4 = 0xFCu;
v5 = 0xFFu;
v6 = 0xE6u;
v7 = 0xF5u;
v8 = 0xE0u;
v9 = 0xF1u;
v10 = 0xF3u;
v11 = 0xFBu;
v12 = 0xF9u;
v13 = 0xFEu;
v14 = 0xF7u;
v15 = 0xFDu;
v16 = 0xE9u;
v17 = 0xF3u;
v18 = 0xFFu;
v19 = 0xF4u;
v20 = 0xF5u;
v21 = 0;
src = calloc(0x141u, 1u);
for ( i = 0; i &amp;lt; n; ++i )
{
v22 = *((_BYTE *)sub_89B + i);
v0 = v22 ^ 0x90;
v1 = strlen(&amp;amp;s);
*((_BYTE *)src + i) = *(&amp;amp;s + i % v1) ^ v0;
}
memcpy(sub_89B, src, n);
return mprotect(addr, v24 - (_BYTE *)addr, 4);
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="tldr"&gt;TL;DR
&lt;/h3&gt;&lt;p&gt;Before we go deep into the details of the single blocks of code, giving a general overview of what its final purpose is, may help its comprehension. First thing, the code changes via &lt;code&gt;mprotect&lt;/code&gt; function the memory protections, adding the write permission, of a specific part of its &lt;code&gt;.text&lt;/code&gt; section. After that, it copies, into the stack, &lt;em&gt;some bytes&lt;/em&gt; that will be revealed as a key for an afterward decryption. Before entering into the main loop, it allocates an array of bytes into the heap via &lt;code&gt;calloc&lt;/code&gt;. Specifically, the length of the array is &lt;code&gt;0x140&lt;/code&gt; bytes; this value is saved into a local variable placed into the stack at &lt;code&gt;[ebp+n]&lt;/code&gt; offset. The main loop is somehow complicated because it xors byte per byte some of its code, placed at &lt;code&gt;sub_89B+i&lt;/code&gt; offset, with a fixed constant &lt;code&gt;0x90&lt;/code&gt; and after, it xors it again with the aforementioned key on the stack. After that, it overwrites the code placed at &lt;code&gt;sub_89B&lt;/code&gt; offset, with these new values via the &lt;code&gt;memcpy&lt;/code&gt; call and returns after changing again the memory protections of that code section back to &lt;code&gt;read-execute&lt;/code&gt;. Let&amp;rsquo;s break in line by line, considering only the useful ones.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-20-alle-21.43.19.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Here, it setups the length of the future array in the variable placed on the stack at &lt;code&gt;[ebp+n]&lt;/code&gt; with the size of &lt;code&gt;0x140&lt;/code&gt; or &lt;code&gt;320&lt;/code&gt; elements of &lt;code&gt;1&lt;/code&gt; byte. After that, it prepares the arguments of the next call to &lt;code&gt;mprotect&lt;/code&gt;, that will change the protection, enabling write permission, on the the address &lt;code&gt;0x5657D000&lt;/code&gt;. Looking up the stack:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-20-alle-21.50.35.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Having &lt;code&gt;ESP&lt;/code&gt; pointing at &lt;code&gt;0xFFC344F0&lt;/code&gt;, the calling convention dictate that the arguments of a function must be pushed into the stack in reverse order. The &lt;code&gt;mprotect&lt;/code&gt; call is defined as: &lt;code&gt;int mprotect(void *addr, size_t len, int prot);&lt;/code&gt; with&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;prot&lt;/code&gt; = &lt;code&gt;6&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;len&lt;/code&gt; = &lt;code&gt;0xE78&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*addr&lt;/code&gt; = &lt;code&gt;0x5657D000&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words: change the permission of the memory area of &lt;code&gt;3704&lt;/code&gt; bytes starting from address &lt;code&gt;0x5657D000&lt;/code&gt;, granting the writability via the &lt;code&gt;PROT_WRITE&lt;/code&gt; constant. More info of this syscall &lt;a class="link" href="http://man7.org/linux/man-pages/man2/mprotect.2.html" target="_blank" rel="noopener"
&gt;here&lt;/a&gt;. But what&amp;rsquo;s inside this address? We&amp;rsquo;re inside the ELF header, basically the start of the entire binary.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/Schermata-2019-03-20-alle-22.13.44.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Going further, we can see the moving into the stack of some bytes, a call to &lt;code&gt;calloc&lt;/code&gt; to allocate an array of &lt;code&gt;320+1&lt;/code&gt; null bytes into the heap and the setup of a loop counter variable, placed at &lt;code&gt;[ebp+var_C]&lt;/code&gt;, with the same size of the array. We&amp;rsquo;re setting up a loop that will scan, byte per byte, a specific area of the binary located at &lt;code&gt;0x5657D89B&lt;/code&gt; - that is a &lt;strong&gt;fixed&lt;/strong&gt; value - and xor every byte, first with &lt;code&gt;0x90&lt;/code&gt; and after with those bytes that were moved into the stack. For better understand this loop, I suggest to read the answer I got &lt;a class="link" href="https://reverseengineering.stackexchange.com/questions/20935/decryption-loops" target="_blank" rel="noopener"
&gt;here&lt;/a&gt;. When this decryption loop ends, we have the decrypted code inside the heap, into the allocated array. Code can now be replaced with the decrypted one via the &lt;code&gt;memcpy&lt;/code&gt; syscall. Finally, write permission can now be disabled and the routine can finish and return.&lt;/p&gt;
&lt;h2 id="second-round-of-conclusions"&gt;Second round of conclusions
&lt;/h2&gt;&lt;p&gt;Many days and months passed staring at me failing so hard into the understanding of this routine. But the feeling was still the same: I wanted to have that &lt;em&gt;&amp;quot;[+] Good job! ;)&amp;quot;&lt;/em&gt; string and I&amp;rsquo;ve always had the &lt;em&gt;Try Harder&lt;/em&gt; approach. Understanding this loop wasn&amp;rsquo;t easy, not even close. I asked for help and, luckily, I got plenty. This is what I got: &lt;strong&gt;don&amp;rsquo;t be afraid to ask for help but don&amp;rsquo;t blindly ask for a solution&lt;/strong&gt;. Work on that, demonstrate that you studied that thing and failed; People, eventually, will get that and will help you.&lt;/p&gt;
&lt;h2 id="towards-the-victory"&gt;Towards the victory
&lt;/h2&gt;&lt;p&gt;After executing the decryption function we land into the code below. First it verifies that the user submitted a password of the length of exactly &lt;code&gt;0x27&lt;/code&gt;, that is a fixed value coming from this instruction: &lt;code&gt;mov eax, (dword_56561058 - 56561000h) [ebx]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/verify_length_password.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Only if the password is exactly &lt;code&gt;39&lt;/code&gt; characters, it moves on into the &lt;code&gt;DecryptedFunction&lt;/code&gt;, passing the user&amp;rsquo;s password as the argument. The previous experience helped a lot to understand this function and the pseudo code generated by IDA is pretty nice.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/dec.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;int __cdecl DecryptedFunction(int UserSubmittedPassword)
{
int result; // eax
char v2; // [esp+0h] [ebp-38h]
char v3; // [esp+1h] [ebp-37h]
char v4; // [esp+2h] [ebp-36h]
char v5; // [esp+3h] [ebp-35h]
char v6; // [esp+4h] [ebp-34h]
char v7; // [esp+5h] [ebp-33h]
char v8; // [esp+6h] [ebp-32h]
char v9; // [esp+7h] [ebp-31h]
char v10; // [esp+8h] [ebp-30h]
char v11; // [esp+9h] [ebp-2Fh]
char v12; // [esp+Ah] [ebp-2Eh]
char v13; // [esp+Bh] [ebp-2Dh]
char v14; // [esp+Ch] [ebp-2Ch]
char v15; // [esp+Dh] [ebp-2Bh]
char v16; // [esp+Eh] [ebp-2Ah]
char v17; // [esp+Fh] [ebp-29h]
char v18; // [esp+10h] [ebp-28h]
char v19; // [esp+11h] [ebp-27h]
char v20; // [esp+12h] [ebp-26h]
char v21; // [esp+13h] [ebp-25h]
char v22; // [esp+14h] [ebp-24h]
char v23; // [esp+15h] [ebp-23h]
char v24; // [esp+16h] [ebp-22h]
char v25; // [esp+17h] [ebp-21h]
char v26; // [esp+18h] [ebp-20h]
char v27; // [esp+19h] [ebp-1Fh]
char v28; // [esp+1Ah] [ebp-1Eh]
char v29; // [esp+1Bh] [ebp-1Dh]
char v30; // [esp+1Ch] [ebp-1Ch]
char v31; // [esp+1Dh] [ebp-1Bh]
char v32; // [esp+1Eh] [ebp-1Ah]
char v33; // [esp+1Fh] [ebp-19h]
char v34; // [esp+20h] [ebp-18h]
char v35; // [esp+21h] [ebp-17h]
char v36; // [esp+22h] [ebp-16h]
char v37; // [esp+23h] [ebp-15h]
char v38; // [esp+24h] [ebp-14h]
char v39; // [esp+25h] [ebp-13h]
char v40; // [esp+26h] [ebp-12h]
unsigned __int8 v41; // [esp+27h] [ebp-11h]
int counter; // [esp+28h] [ebp-10h]
int v43; // [esp+2Ch] [ebp-Ch]
v43 = 0;
v2 = 0x93u;
v3 = 0x5E;
v4 = 0xB0u;
v5 = 0xB8u;
v6 = 0xC5u;
v7 = 0xD7u;
v8 = 0xACu;
v9 = 0x23;
v10 = 0xC3u;
v11 = 0xF0u;
v12 = 6;
v13 = 0x72;
v14 = 0xF4u;
v15 = 0x74;
v16 = 0x93u;
v17 = 0x52;
v18 = 0x74;
v19 = 0x72;
v20 = 0x30;
v21 = 0xEDu;
v22 = 0x8Bu;
v23 = 0x3D;
v24 = 4;
v25 = 0x58;
v26 = 0xD8u;
v27 = 0xE5u;
v28 = 0xA2u;
v29 = 0xCFu;
v30 = 0x8Au;
v31 = 0xEDu;
v32 = 0x8Bu;
v33 = 0x5C;
v34 = 0x5E;
v35 = 0x61;
v36 = 0xDCu;
v37 = 0x31;
v38 = 0xCFu;
v39 = 0x91u;
v40 = 0x82u;
for ( counter = 0; counter &amp;lt; PasswordLength; ++counter )
{
v41 = *((_BYTE *)AntiAnalysisFunction + counter + 0xC7);
if ( (v41 ^ *(_BYTE *)(counter + UserSubmittedPassword)) != *(&amp;amp;v2 + counter) )
{
v43 = 1;
break;
}
}
if ( v43 )
result = puts(&amp;#34;[-] Nope!&amp;#34;);
else
result = puts(&amp;#34;[+] Good job! ;)&amp;#34;);
return result;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It scans the user&amp;rsquo;s password, character by character, xoring it with a string retrieved from the binary itself. If every character matches it goes on and continue in the loop, otherwise it breaks. In the end, if everything is correct, it prints the beloved success string. How can we retrieve the correct flag? If we dump the &lt;code&gt;39&lt;/code&gt; bytes from the binary, from the correct addresses, and xor them with the hardcoded string, we can take advantage of the xor bidirectional nature. Although you can find more details &lt;a class="link" href="https://en.wikipedia.org/wiki/Exclusive_or" target="_blank" rel="noopener"
&gt;here&lt;/a&gt;, we&amp;rsquo;re basically telling this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;A xor B = C
A xor C = B
B xor C = A
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;My first approach was to &lt;em&gt;bruteforce&lt;/em&gt; the routine: if the string submitted is, eventually, &lt;code&gt;\x41\x41\x41\x41\x41\x41\x41...&lt;/code&gt; we can step by step into the code and go into the final &lt;code&gt;cmp&lt;/code&gt; instruction, retrieve the byte that it compares to and change the ZERO flag to force the loop to continue and not to stop. Otherwise we can dump the contents of the memory and xor with the hardcoded string, as result we get the flag that needs to be submitted to the binary.&lt;/p&gt;
&lt;p&gt;We know that we need to get &lt;code&gt;39&lt;/code&gt; bytes from address &lt;code&gt;*((_BYTE *)AntiAnalysisFunction + 0 + 0xC7)&lt;/code&gt; to &lt;code&gt;*((_BYTE *)AntiAnalysisFunction + 0x27 + 0xC7)&lt;/code&gt;. Or from  &lt;code&gt;(0x5662A9DC + 0 + 0xC7) = 0x5662AAA3&lt;/code&gt; to &lt;code&gt;0x5662AACA = (0x5662A9DC + 0x27 + 0xC7)&lt;/code&gt;. We can apply the xor operation with the known string and we&amp;rsquo;re able retrieve the flag, finally.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Hardcoded: 93 5E B0 B8 C5 D7 AC 23 C3 F0 06 72 F4 74 93 52 74 72 30 ED 8B 3D 04 58 D8 E5 A2 CF 8A ED 8B 5C 5E 61 DC 31 CF 91 82
Memory dump: E8 18 FC FF FF 83 C4 10 85 C0 74 11 C7 45 E0 01 00 00 00 83 EC 0C 6A 01 E8 90 FB FF FF 83 EC 0C 6A 05 E8 46 FB FF FF
Flag hex: 7B 46 4C 47 3A 54 68 33 46 30 72 63 33 31 73 53 74 72 30 6E 67 31 6E 59 30 75 59 30 75 6E 67 50 34 64 34 77 34 6E 7D
Flag ascii: { F L G : T h 3 F 0 r c 3 1 s S t r 0 n g 1 n Y 0 u Y 0 u n g P 4 d 4 w 4 n }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/03/victory.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h2 id="conclusions"&gt;Conclusions
&lt;/h2&gt;&lt;p&gt;This was a long journey that required a lot of effort and countless sleepless nights. It was worth it? &lt;strong&gt;Every single minute, without any doubt&lt;/strong&gt;. I hope this post will help you in your studies and if you spot any errors or want to help me in my journey into the reverse engineering world please leave a comment, tweet or e-mail.&lt;/p&gt;
&lt;p&gt;As always, &lt;strong&gt;Try Harder&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>Reverse engineering the router Technicolor TG582N</title><link>https://blog.kartone.ninja/reverse-engineering-the-router-technicolor-tg582n/</link><pubDate>Thu, 07 Feb 2019 09:00:00 +0000</pubDate><guid>https://blog.kartone.ninja/reverse-engineering-the-router-technicolor-tg582n/</guid><description>&lt;img src="https://blog.kartone.ninja/images/2019/02/st2_mezzanine_18st.jpeg" alt="Featured image of post Reverse engineering the router Technicolor TG582N" /&gt;&lt;p&gt;During last months, my interest in hardware hacking got an exponential growth due to the fact I had the chance to get my hands on some so-ho routers unretired from local Telcos. So what a great opportunity to open and try to crack them, without worrying about irreparable damage?&lt;/p&gt;
&lt;h2 id="inspecting-the-device"&gt;Inspecting the device
&lt;/h2&gt;&lt;p&gt;My first device was the &lt;code&gt;Technicolor TG582N&lt;/code&gt; distributed in Italy by Fastweb.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-4.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Front side&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-3.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Back side&lt;/p&gt;
&lt;p&gt;Nothing too much interesting externally: for this purpose, common useless informations about wireless access code, serial number, mac-address, etc.&lt;/p&gt;
&lt;p&gt;A much more interesting view is the internal one: I was able to remove the two lower screws, under the rubbers and, with a gentle lever, the upper part can be unhooked giving access to the router motherboard.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-2.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Router motherboard with the relevant ICs&lt;/p&gt;
&lt;h2 id="internal-components-analysis"&gt;Internal components analysis
&lt;/h2&gt;&lt;p&gt;A pretty standard design for this kind of device, we can clearly see the main CPU &lt;strong&gt;Broadcom BCM63281KFBG&lt;/strong&gt; and its two memory ICs (&lt;em&gt;Integrated Circuits&lt;/em&gt;): RAM and Flash memory. There&amp;rsquo;s also another Broadcom chip but its role is to manage wireless functionalities and, for now, is out of scope.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-7.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Winbond W9751G6KB-25&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-6.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spansion FL064PIF&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For the volatile data, the device uses a DDR2 SDRAM module produced by Winbond with the capacity 512 Mbit (64 MByte). Obviously I&amp;rsquo;m interested in the EEPROM chip, because it&amp;rsquo;s where the non-volatile data is stored and persists across reboots and shutdowns. This device has a flash memory module produced by Spansion (now Cypress) with the capacity of 64 Mbit (8 Mbyte).&lt;/p&gt;
&lt;h2 id="accessing-to-uart-console"&gt;Accessing to UART console
&lt;/h2&gt;&lt;p&gt;I didn&amp;rsquo;t put too much effort in this because the nice guys of OpenWRT project did all the &lt;a class="link" href="https://openwrt.org/toh/thomson/tg582n" target="_blank" rel="noopener"
&gt;dirty job&lt;/a&gt;. Although the board perfectly matches to the devices described in that page, I noted a slight difference on the EEPROM chip. They mention three board type: DANT-1, DANT-T, and DANT-V. These boards have three types of EEPROM chip but none of them have this Spansion chip, only the DANT-V version has a Spansion chip but it&amp;rsquo;s an FL129P, a 128 Mbit flash memory. We&amp;rsquo;re definitely dealing with a slightly smaller memory chip. Anyway, UART pins are the same of other boards and we need to solder 3 pins (Tx, Rx, and GND) and short circuit R62 and R63 as noted in the above link.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-11.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Soldered UART pins&lt;/p&gt;
&lt;p&gt;After this little soldering, we can attach a &lt;a class="link" href="https://www.amazon.it/dp/B07BBPX8B8/ref=cm_sw_em_r_mt_dp_U_qpKmCbXHWAKN8" target="_blank" rel="noopener"
&gt;common interface&lt;/a&gt; based on the &lt;code&gt;FTD232&lt;/code&gt; and have a console access. Remember to NOT attach the &lt;code&gt;VCC&lt;/code&gt; pin because the required power will be provided by the standard supply.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-12.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;With this simple setup we can finally have access to the router console and see all the boot messages:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Welcome to minicom 2.7.1
OPTIONS: I18n
Compiled on May 3 2018, 15:20:11.
Port /dev/ttyUSB0, 17:40:25
Press CTRL-A Z for help on special keys
D%G
Decompressing Bootloader..............................
Gateway initialization sequence started.
Version BL: 1.0.5
Multicore disable; Booting Linux kernel
BOOTING THE LINUX KERNEL
Starting the kernel @ 0x801dfcd0
Extra parameters passed to Linux:
[0]: bootloader
[1]: memsize=0x3EDD000
Linux version 2.6.30 (gcc version 3.4.6) #1 Mon Mar 26 18:25:38 CST 2012
BCM63XX prom init
CPU revision is: 0002a075 (Broadcom4350)
Determined physical RAM map:
memory: 03edb000 @ 00002000 (usable)
Wasting 64 bytes for tracking 2 unused pages
Zone PFN ranges:
DMA 0x00000002 -&amp;gt; 0x00001000
Normal 0x00001000 -&amp;gt; 0x00003edd
Movable zone start PFN for each node
early_node_map[1] active PFN ranges
0: 0x00000002 -&amp;gt; 0x00003edd
On node 0 totalpages: 16091
free_area_init_node: node 0, pgdat 80238480, node_mem_map 81000040
DMA zone: 32 pages used for memmap
DMA zone: 0 pages reserved
DMA zone: 4062 pages, LIFO batch:0
Normal zone: 94 pages used for memmap
Normal zone: 11903 pages, LIFO batch:1
Built 1 zonelists in Zone order, mobility grouping on. Total pages: 15965
Kernel command line: root=31:0 ro noinitrd memsize=0x3EDD000 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=squashfs
wait instruction: enabled
Primary instruction cache 32kB, VIPT, 4-way, linesize 16 bytes.
Primary data cache 32kB, 2-way, VIPT, cache aliases, linesize 16 bytes
NR_IRQS:128
PID hash table entries: 256 (order: 8, 1024 bytes)
console [ttyS0] enabled
Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
Memory: 61152k/64364k available (1882k kernel code, 3192k reserved, 331k data, 108k init, 0k highmem)
Calibrating delay loop... 318.46 BogoMIPS (lpj=159232)
Mount-cache hash table entries: 512
--Kernel Config--
SMP=0
PREEMPT=0
DEBUG_SPINLOCK=0
DEBUG_MUTEXES=0
net_namespace: 584 bytes
NET: Registered protocol family 16
registering PCI controller with io_map_base unset
registering PCI controller with io_map_base unset
bio: create slab &amp;lt;bio-0&amp;gt; at 0
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
pci 0000:00:09.0: reg 10 32bit mmio: [0x10002600-0x100026ff]
pci 0000:00:0a.0: reg 10 32bit mmio: [0x10002500-0x100025ff]
pci 0000:01:00.0: PME# supported from D0 D3hot
pci 0000:01:00.0: PME# disabled
pci 0000:02:00.0: reg 10 64bit mmio: [0x000000-0x003fff]
pci 0000:02:00.0: supports D1 D2
pci 0000:01:00.0: PCI bridge, secondary bus 0000:02
pci 0000:01:00.0: IO window: disabled
pci 0000:01:00.0: MEM window: 0x10f00000-0x10ffffff
pci 0000:01:00.0: PREFETCH window: disabled
PCI: Enabling device 0000:01:00.0 (0000 -&amp;gt; 0002)
PCI: Setting latency timer of device 0000:01:00.0 to 64
BLOG Rule v1.0 Initialized
Broadcom IQoS v0.1 Mar 26 2012 18:23:40 initialized
NET: Registered protocol family 2
IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
TCP established hash table entries: 2048 (order: 2, 16384 bytes)
TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
TCP: Hash tables configured (established 2048 bind 2048)
TCP reno registered
NET: Registered protocol family 1
squashfs: version 4.0 (2009/01/31) Phillip Lougher
squashfs: version 4.0 with LZMA457 ported by BRCM
JFFS2 version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
msgmni has been set to 119
io scheduler noop registered (default)
pcieport-driver 0000:01:00.0: device [14e4:6328] has invalid IRQ; check vendor BIOS
PCI: Setting latency timer of device 0000:01:00.0 to 64
Gateway flash mapping
flash mapping initialized
Creating 4 MTD partitions on &amp;#34;thomson-spi&amp;#34;:
0x000000040000-0x0000000b0000 : &amp;#34;userfs&amp;#34;
0x000000020000-0x000000040000 : &amp;#34;mtdss&amp;#34;
0x000000180000-0x000000800000 : &amp;#34;rootfs&amp;#34;
0x0000000b0000-0x000000180000 : &amp;#34;kernel&amp;#34;
brcmboard: brcm_board_init entry
Serial: BCM63XX driver $Revision: 3.00 $
ttyS0 at MMIO 0xb0000100 (irq = 36) is a BCM63XX
ttyS1 at MMIO 0xb0000100 (irq = 36) is a BCM63XX
ttyS2 at MMIO 0xb0000120 (irq = 47) is a BCM63XX
TCP cubic registered
NET: Registered protocol family 17
NET: Registered protocol family 15
VFS: Mounted root (squashfs filesystem) readonly on device 31:2.
Freeing unused kernel memory: 108k freed
init started: BusyBox v1.00 (2012.03.26-10:27+0000) multi-call binary
init started: BusyBox v1.00 (2012.03.26-10:27+0000) multi-call binary
Starting pid 116, console /dev/ttyS0: &amp;#39;/etc/init.d/rcS&amp;#39;
Initializing random number generator
Using /lib/modules/kserport.ko
kserport: module license &amp;#39;unspecified&amp;#39; taints kernel.
Disabling lock debugging due to kernel taint
Using /nmon/nmon.ko
loading geniodb kernel modules...
Using /lib/modules/geniodb.ko
geniodb driver: Loading ...
geniodb driver: Loading finished with SUCCESS
Button char device has been created and initialized.
[BCM ADSL] BcmAdsl_SetOverlayMode = 85 new=0
tmm_skb_desc.queuesize = 300
queue: 0xc09aa744
queue: 0xc09aa744, rp: 0xc09aa744, wp: 0xc09aa744
[BCM ADSL] ------ dslFileLoadImage : OverlayMode = 0 fname=ZXD3AA
pci 0000:00:09.0: firmware: requesting ZXD3AA
pSdramPHY=0xA3FFFFF8, 0x5CF9A 0xDEADBEEF
[BCM ADSL] Firmware load : 548088 548088 LMEM=(0xB0D80000, 11380) SDRAM=(0xA3F00000, 536700)
pci 0000:00:09.0: firmware: requesting phy
*** PhySdramSize got adjusted: 0x8307C =&amp;gt; 0x98A20 ***
AdslCoreSharedMemInit: shareMemAvailable=423360
AdslCoreHwReset: pLocSbSta=c09a2fd0 bkupThreshold=1600
AdslCoreHwReset: AdslOemDataAddr = 0xA3F78090
[DSL driver] !-!-!-!-!-!-! ***** AFE ID = 0x1040a200
ADSL PHY version is A2pDT002a.d23k
b6w_init
FOUND WL DEVICE 0, bus=2, device=0, func=0, vendorid=14E4, deviceid=A8DC, regaddr=10F00000, irq=31
wl:srom not detected, using main memory mapped srom info(wombo board)
veth0 (): not using net_device_ops yet
NET: Registered protocol family 3
NET: Registered protocol family 9
NET: Registered protocol family 6
NET: Registered protocol family 4
NET: Registered protocol family 5
NET: Registered protocol family 18
NET: Registered protocol family 25
Device ipsec not present.
voice will be loaded
Device endpoint not present.
Device ikanos not present.
Starting pid 338, console /dev/ttyS0: &amp;#39;/etc/init.d/rc&amp;#39;
Switching to RUNLEVEL 1 ...
Disabling hotplug helper
route: SIOC[ADD|DEL]RT: File exists
linux application start ...
wait for linux_appl to initialize (1)
wait for linux_appl to initialize (2)
************* ERROR RECORD *************
000000:00:00.000000
Application NMON started after POWERON.
****************** END *****************
wait for linux_appl to initialize (3)
appl_init: BUILD VERIFIED!
wait for linux_appl to initialize (4)
[SS EMUL] ERR: opening config file /active/ss.conf failed
End of initialisation
wait for linux_appl to initialize (5)
start fseventd ...
fseventd is started.
start storagepl ...
storagepl is started
start vfspl ...
vfspl is started
MVFS plugin started
cifs plug-in: initializing ...
cifs plug-in is started
upnpavpl start ...
/usr/bin/fusermount
Loading fuse modulefuse init (API version 7.11)
.
Mounting fuse control filesystem.
linuxappl: start loading after [ 4459ms ]
WARNING: Unknown Parameter Type ifmfilter
WARNING: Unknown Parameter Type ifmfilter
S67stopload: wait until configuration load reaches phase 9...
S67stopload: wait until configuration load reaches phase 9 (now -1, 1s)
adsl: adsl_open entry
ADSL Line state is: DOWN
[adsl] trace = 5 0
S67stopload: wait until configuration load reaches phase 9 (now -1, 2s)
The OBC bridge interface cannot be removed from this VLAN, because OBC is defined as untagged.
S67stopload: wait until configuration load reaches phase 9 (now 3, 3s)
S67stopload: wait until configuration load reaches phase 9 (now 3, 4s)
S67stopload: wait until configuration load reaches phase 9 (now 3, 5s)
S67stopload: wait until configuration load reaches phase 9 (now 3, 6s)
S67stopload: wait until configuration load reaches phase 9 (now 3, 7s)
DyingGasp RIP BIT is set!
[ERROR : [DIAG 1004] -1 ]
ADSL configuration:
adslmultimode = adsl2plus
syslog = disabled
S67stopload: wait until configuration load reaches phase 9 (now 3, 8s)
S67stopload: wait until configuration load reaches phase 9 (now 3, 9s)
The OBC bridge interface cannot be removed from this VLAN, because OBC is defined as untagged.
Option not allowed =&amp;gt; HostNotLocalDomain
Unsupported URL. The url must include http:// or https://.
Failed to add host 9c:97:26:0c:0c:e9
S67stopload: wait until configuration load reaches phase 9 (now 6, 10s)
S67stopload: wait until configuration load reaches phase 9 (now 6, 11s)
S67stopload: wait until configuration load reaches phase 9 (now 6, 12s)
S67stopload: configuration load reached phase 9...
Intel MicroStack 1.0 - Digital Media Server (DLNA 1.5)(pid = 835),
loc_generate_uuid:25e05aa9-8206-5b77-9aad-d5547194a957
nlplugd start ...
Initializing.
Starting netlink plugin
Daemonize netlink plugin
udhcpcd start ...
monitoripd start ...
anti_spoofd start ...
anti_spoofd : process exit !
start mud ...
Using /lib/modules/2.6.30/kernel/drivers/usb/host/ehci-hcd.ko
ehci_hcd: USB 2.0 &amp;#39;Enhanced&amp;#39; Host Controller (EHCI) Driver
PCI: Enabling device 0000:00:0a.0 (0000 -&amp;gt; 0002)
PCI: Setting latency timer of device 0000:00:0a.0 to 64
ehci_hcd 0000:00:0a.0: EHCI Host Controller
ehci_hcd 0000:00:0a.0: new USB bus registered, assigned bus number 1
ehci_hcd 0000:00:0a.0: Enabling legacy PCI PM
ehci_hcd 0000:00:0a.0: irq 50, io mem 0x10002500
ehci_hcd 0000:00:0a.0: USB f.f started, EHCI 1.00
monitoripd start ...
anti_spoofd start ...
anti_spoofd : process exit !
start mud ...
Using /lib/modules/2.6.30/kernel/drivers/usb/host/ehci-hcd.ko
ehci_hcd: USB 2.0 &amp;#39;Enhanced&amp;#39; Host Controller (EHCI) Driver
PCI: Enabling device 0000:00:0a.0 (0000 -&amp;gt; 0002)
PCI: Setting latency timer of device 0000:00:0a.0 to 64
ehci_hcd 0000:00:0a.0: EHCI Host Controller
ehci_hcd 0000:00:0a.0: new USB bus registered, assigned bus number 1
ehci_hcd 0000:00:0a.0: Enabling legacy PCI PM
ehci_hcd 0000:00:0a.0: irq 50, io mem 0x10002500
ehci_hcd 0000:00:0a.0: USB f.f started, EHCI 1.00
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
Using /lib/modules/2.6.30/kernel/drivers/usb/host/ohci-hcd.ko
ohci_hcd: USB 1.1 &amp;#39;Open&amp;#39; Host Controller (OHCI) Driver
PCI: Enabling device 0000:00:09.0 (0000 -&amp;gt; 0002)
PCI: Setting latency timer of device 0000:00:09.0 to 64
ohci_hcd 0000:00:09.0: OHCI Host Controller
ohci_hcd 0000:00:09.0: new USB bus registered, assigned bus number 2
ohci_hcd 0000:00:09.0: irq 49, io mem 0x10002600
usb usb2: configuration #1 chosen from 1 choice
hub 2-0:1.0: USB hub found
hub 2-0:1.0: 1 port detected
Using /lib/modules/2.6.30/kernel/drivers/usb/class/usblp.ko
usbcore: registered new interface driver usblp
Using /lib/modules/2.6.30/kernel/drivers/usb/serial/usbserial.ko
usbcore: registered new interface driver usbserial
USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
Using /lib/modules/2.6.30/kernel/drivers/scsi/scsi_mod.ko
SCSI subsystem initialized
Using /lib/modules/2.6.30/kernel/drivers/scsi/sd_mod.ko
Driver &amp;#39;sd&amp;#39; needs updating - please use bus_type methods
Using /lib/modules/2.6.30/kernel/drivers/usb/storage/usb-storage.ko
Initializing USB Mass Storage driver...
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
Using /lib/modules/2.6.30/kernel/fs/fat/fat.ko
Using /lib/modules/2.6.30/kernel/fs/fat/vfat.ko
Using /lib/modules/2.6.30/kernel/fs/nls/nls_cp437.ko
Using /lib/modules/2.6.30/kernel/fs/nls/nls_iso8859-1.ko
Using /lib/modules/2.6.30/kernel/fs/nls/nls_cp850.ko
Name: /etc/usbmgr/usbmgr.conf
Starting power manager...
Username :
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After the boot, there&amp;rsquo;s the good old login screen but without a valid username/password there&amp;rsquo;s not much we can do. One way to proceed is to investigate the filesystem without any sort of access control. Filesystem can be obtained by dumping it directly from the flash memory.&lt;/p&gt;
&lt;h2 id="dumping-the-flash"&gt;Dumping the flash
&lt;/h2&gt;&lt;p&gt;Reading the flash memory contents is not something overcomplicated but requires a bit of understanding of how integrated circuits work and how you can obtain the raw contents of the chip using the same interfaces and protocols used by the main CPU during the normal operation of the device.&lt;/p&gt;
&lt;p&gt;For this purpose we&amp;rsquo;re targeting the flash memory chip that was inspected above: a Spansion chip &lt;code&gt;FL064pif&lt;/code&gt; with its datasheet is available on the manufacture site.&lt;/p&gt;
&lt;p&gt;In order to read - and eventually write - its contents, we need to interface with the chip itself, using its pins and using a serial protocol, named &lt;code&gt;SPI&lt;/code&gt;. The useful pins are &lt;code&gt;Vcc, CS, SO, SI, SCK and GND&lt;/code&gt;and their description is available on the datasheet.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-15.png"
loading="lazy"
&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-20.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Dumping the chip can be done with &lt;code&gt;BusPirate&lt;/code&gt; and &lt;code&gt;Flashrom&lt;/code&gt;. In order to avoid any desoldering, we&amp;rsquo;ll use a &lt;code&gt;Pomona SOIC clip model 5252&lt;/code&gt;. In this case, power we&amp;rsquo;ll be supplied by the BusPirate itself and the board must be &lt;strong&gt;switched off&lt;/strong&gt;. This is because we don&amp;rsquo;t want any interaction from the main CPU that will interfere with the memory chip while we&amp;rsquo;re dumping its contents.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-16.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;h3 id="in-system-programming"&gt;In-system programming
&lt;/h3&gt;&lt;p&gt;In this case we were lucky, because powering up the chip itself didn&amp;rsquo;t wake up any other component of the board, like the main CPU. This can happens and depends on how the board is designed and how the components are connected and can vary from board to board. If there&amp;rsquo;s such interference you&amp;rsquo;ll end up with a &lt;a class="link" href="https://reverseengineering.stackexchange.com/questions/20127/unable-to-unsquash-from-a-firmware-dump" target="_blank" rel="noopener"
&gt;corrupted dump&lt;/a&gt; and &lt;em&gt;flashrom won&amp;rsquo;t alert you in that case&lt;/em&gt;. This is why it&amp;rsquo;s a good practice to verify the correctness of the dumping process.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-17.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Dumping the flash&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2019/01/image-9.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Verifying the dump&lt;/p&gt;
&lt;p&gt;We now have the entire content of the flash memory. We can read, eventually, &lt;code&gt;bootloader&lt;/code&gt;, &lt;code&gt;Linux kernel&lt;/code&gt; and, more interesting, the &lt;code&gt;root filesystem&lt;/code&gt;. Basically we have the entire software stack the manufacturer has deployed on the device.&lt;/p&gt;
&lt;h2 id="firmware-extraction"&gt;Firmware extraction
&lt;/h2&gt;&lt;p&gt;For the extraction we will use the &lt;a class="link" href="https://github.com/ReFirmLabs/binwalk" target="_blank" rel="noopener"
&gt;Binwalk&lt;/a&gt; utility. It will read the dump and try to recognize and extract any known file format.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:~/Projects/tg582n# binwalk dump.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
45066 0xB00A LZMA compressed data, properties: 0x5D, dictionary size: 2097152 bytes, uncompressed size: 250804 bytes
132350 0x204FE PEM certificate
133927 0x20B27 PEM certificate
135518 0x2115E PEM certificate
262144 0x40000 JFFS2 filesystem, big endian
262496 0x40160 Zlib compressed data, compressed
262760 0x40268 JFFS2 filesystem, big endian
267824 0x41630 Zlib compressed data, compressed
269016 0x41AD8 Zlib compressed data, compressed
269332 0x41C14 Zlib compressed data, compressed
269648 0x41D50 Zlib compressed data, compressed
269844 0x41E14 JFFS2 filesystem, big endian
269960 0x41E88 Zlib compressed data, compressed
270176 0x41F60 Zlib compressed data, compressed
270444 0x4206C Zlib compressed data, compressed
270892 0x4222C Zlib compressed data, compressed
271452 0x4245C Zlib compressed data, compressed
271552 0x424C0 JFFS2 filesystem, big endian
272436 0x42834 Zlib compressed data, compressed
273012 0x42A74 Zlib compressed data, compressed
273548 0x42C8C Zlib compressed data, compressed
273888 0x42DE0 Zlib compressed data, compressed
274424 0x42FF8 Zlib compressed data, compressed
274764 0x4314C Zlib compressed data, compressed
275300 0x43364 Zlib compressed data, compressed
275640 0x434B8 Zlib compressed data, compressed
276136 0x436A8 Zlib compressed data, compressed
276476 0x437FC Zlib compressed data, compressed
277052 0x43A3C Zlib compressed data, compressed
277268 0x43B14 Zlib compressed data, compressed
277536 0x43C20 Zlib compressed data, compressed
278608 0x44050 Zlib compressed data, compressed
279672 0x44478 Zlib compressed data, compressed
280084 0x44614 JFFS2 filesystem, big endian
280200 0x44688 Zlib compressed data, compressed
280684 0x4486C JFFS2 filesystem, big endian
280872 0x44928 Zlib compressed data, compressed
281124 0x44A24 Zlib compressed data, compressed
281240 0x44A98 Zlib compressed data, compressed
281336 0x44AF8 Zlib compressed data, compressed
281432 0x44B58 Zlib compressed data, compressed
281460 0x44B74 JFFS2 filesystem, big endian
281676 0x44C4C Zlib compressed data, compressed
281768 0x44CA8 Zlib compressed data, compressed
281864 0x44D08 Zlib compressed data, compressed
281960 0x44D68 Zlib compressed data, compressed
282056 0x44DC8 Zlib compressed data, compressed
282176 0x44E40 Zlib compressed data, compressed
282300 0x44EBC Zlib compressed data, compressed
282668 0x4502C JFFS2 filesystem, big endian
282808 0x450B8 Zlib compressed data, compressed
282932 0x45134 Zlib compressed data, compressed
283152 0x45210 JFFS2 filesystem, big endian
283772 0x4547C Zlib compressed data, compressed
284068 0x455A4 Zlib compressed data, compressed
284624 0x457D0 JFFS2 filesystem, big endian
285552 0x45B70 Zlib compressed data, compressed
286000 0x45D30 JFFS2 filesystem, big endian
286764 0x4602C Zlib compressed data, compressed
287224 0x461F8 JFFS2 filesystem, big endian
288020 0x46514 Zlib compressed data, compressed
288456 0x466C8 JFFS2 filesystem, big endian
289736 0x46BC8 Zlib compressed data, compressed
290484 0x46EB4 JFFS2 filesystem, big endian
291892 0x47434 Zlib compressed data, compressed
292352 0x47600 JFFS2 filesystem, big endian
293416 0x47A28 Zlib compressed data, compressed
294336 0x47DC0 JFFS2 filesystem, big endian
295984 0x48430 Zlib compressed data, compressed
296564 0x48674 JFFS2 filesystem, big endian
297632 0x48AA0 Zlib compressed data, compressed
298040 0x48C38 JFFS2 filesystem, big endian
299428 0x491A4 Zlib compressed data, compressed
299856 0x49350 JFFS2 filesystem, big endian
300880 0x49750 Zlib compressed data, compressed
301620 0x49A34 JFFS2 filesystem, big endian
303128 0x4A018 Zlib compressed data, compressed
303684 0x4A244 JFFS2 filesystem, big endian
304808 0x4A6A8 Zlib compressed data, compressed
305152 0x4A800 JFFS2 filesystem, big endian
305828 0x4AAA4 Zlib compressed data, compressed
306220 0x4AC2C JFFS2 filesystem, big endian
306940 0x4AEFC Zlib compressed data, compressed
307904 0x4B2C0 JFFS2 filesystem, big endian
309392 0x4B890 Zlib compressed data, compressed
309908 0x4BA94 JFFS2 filesystem, big endian
313324 0x4C7EC Zlib compressed data, compressed
313900 0x4CA2C Zlib compressed data, compressed
314436 0x4CC44 Zlib compressed data, compressed
314776 0x4CD98 Zlib compressed data, compressed
315312 0x4CFB0 Zlib compressed data, compressed
315652 0x4D104 Zlib compressed data, compressed
316188 0x4D31C Zlib compressed data, compressed
316528 0x4D470 Zlib compressed data, compressed
317024 0x4D660 Zlib compressed data, compressed
317364 0x4D7B4 Zlib compressed data, compressed
317940 0x4D9F4 Zlib compressed data, compressed
318236 0x4DB1C Zlib compressed data, compressed
319308 0x4DF4C Zlib compressed data, compressed
320616 0x4E468 Zlib compressed data, compressed
323744 0x4F0A0 JFFS2 filesystem, big endian
323884 0x4F12C Zlib compressed data, compressed
323944 0x4F168 JFFS2 filesystem, big endian
591524 0x906A4 Zlib compressed data, compressed
592100 0x908E4 Zlib compressed data, compressed
592808 0x90BA8 Zlib compressed data, compressed
593516 0x90E6C Zlib compressed data, compressed
594224 0x91130 Zlib compressed data, compressed
594892 0x913CC Zlib compressed data, compressed
595468 0x9160C Zlib compressed data, compressed
595764 0x91734 Zlib compressed data, compressed
596836 0x91B64 Zlib compressed data, compressed
598144 0x92080 Zlib compressed data, compressed
599460 0x925A4 Zlib compressed data, compressed
600036 0x927E4 Zlib compressed data, compressed
600744 0x92AA8 Zlib compressed data, compressed
601452 0x92D6C Zlib compressed data, compressed
602160 0x93030 Zlib compressed data, compressed
602828 0x932CC Zlib compressed data, compressed
603404 0x9350C Zlib compressed data, compressed
603700 0x93634 Zlib compressed data, compressed
604772 0x93A64 Zlib compressed data, compressed
606080 0x93F80 Zlib compressed data, compressed
606568 0x94168 JFFS2 filesystem, big endian
607900 0x9469C Zlib compressed data, compressed
608608 0x94960 Zlib compressed data, compressed
609316 0x94C24 Zlib compressed data, compressed
610024 0x94EE8 Zlib compressed data, compressed
610692 0x95184 Zlib compressed data, compressed
611200 0x95380 JFFS2 filesystem, big endian
611564 0x954EC Zlib compressed data, compressed
612568 0x958D8 JFFS2 filesystem, big endian
613128 0x95B08 JFFS2 filesystem, big endian
720922 0xB001A LZMA compressed data, properties: 0x5D, dictionary size: 2097152 bytes, uncompressed size: 2394632 bytes
1572864 0x180000 Squashfs filesystem, little endian, non-standard signature, version 4.0, compression:gzip, size: 6626892 bytes, 1298 inodes, blocksize: 131072 bytes, created: 2012-10-15 13:38:44
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Honestly, this is the first time I had so much results from binwalk. The first thing I noted is the &lt;code&gt;SquashFS&lt;/code&gt; signature. From the boot log messages, we know that the root filesystem is in that format:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Kernel command line: root=31:0 ro noinitrd memsize=0x3EDD000 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=squashfs
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So we&amp;rsquo;ll start to dig in that directory first:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:~/Projects/tg582n/_dump.bin.extracted/squashfs-root# ll
total 68K
drwxrwxr-x 15 root root 4,0K ott 15 2012 .
drwxr-xr-x 34 root root 12K gen 20 12:06 ..
drwxrwxr-x 3 root root 4,0K ott 15 2012 archive
drwxrwxrwx 2 root root 4,0K mar 26 2012 bin
drwxrwxrwx 6 root root 4,0K mar 26 2012 dev
lrwxrwxrwx 1 root root 6 mar 26 2012 dl -&amp;gt; /rw/dl
drwxrwxr-x 10 root root 4,0K mar 26 2012 etc
drwxrwxrwx 3 root root 4,0K mar 26 2012 lib
drwxrwxrwx 2 root root 4,0K mar 26 2012 nmon
drwxrwxrwx 2 root root 4,0K mar 26 2012 proc
drwxrwxrwx 3 root root 4,0K mar 26 2012 rw
drwxrwxrwx 2 root root 4,0K mar 26 2012 sbin
drwxrwxrwx 2 root root 4,0K mar 26 2012 sys
lrwxrwxrwx 1 root root 8 mar 26 2012 tmp -&amp;gt; /var/tmp
drwxrwxrwx 2 root root 4,0K mar 26 2012 userfs
drwxrwxrwx 5 root root 4,0K mar 26 2012 usr
drwxrwxrwx 2 root root 4,0K mar 26 2012 var
root@kali:~/Projects/tg582n/_dump.bin.extracted/squashfs-root#
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&amp;rsquo;re interested into &lt;code&gt;passwd&lt;/code&gt; file but looking up in the &lt;code&gt;/etc&lt;/code&gt; directory, we find that, like most embedded device, that file is autogenerated and what we see is only a placeholder.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;root@kali:~/Projects/tg582n/_dump.bin.extracted/squashfs-root/etc# ll
total 100K
drwxrwxr-x 10 root root 4,0K mar 26 2012 .
drwxrwxr-x 15 root root 4,0K ott 15 2012 ..
-rw-r--r-- 1 root root 513 mar 26 2012 advancedservices.conf
-r--r--r-- 1 root root 377 mar 26 2012 autoconf.conf
-r--r--r-- 1 root root 133 mar 26 2012 autoip.conf
drwxrwxrwx 2 root root 4,0K mar 26 2012 config
-rw-rw-rw- 1 root root 345 mar 26 2012 fileprofiler.conf
-r--r--r-- 1 root root 73 mar 26 2012 fstab
-r--r--r-- 1 root root 17 mar 26 2012 fuse.conf
lrwxrwxrwx 1 root root 15 mar 26 2012 group -&amp;gt; ../rw/etc/group
lrwxrwxrwx 1 root root 17 mar 26 2012 gshadow -&amp;gt; ../rw/etc/gshadow
-r--r--r-- 1 root root 26 mar 26 2012 host.conf
drwxrwxr-x 2 root root 4,0K mar 26 2012 init.d
-r--r--r-- 1 root root 513 mar 26 2012 inittab
-r--r--r-- 1 root root 17K mar 26 2012 mime.types
lrwxrwxrwx 1 root root 14 mar 26 2012 mtab -&amp;gt; ../proc/mounts
-r--r--r-- 1 root root 465 mar 26 2012 nsswitch.conf
lrwxrwxrwx 1 root root 16 mar 26 2012 passwd -&amp;gt; ../rw/etc/passwd
drwxr-xr-x 2 root root 4,0K mar 26 2012 rc0.d
drwxr-xr-x 2 root root 4,0K mar 26 2012 rc1.d
drwxr-xr-x 2 root root 4,0K mar 26 2012 rc2.d
drwxr-xr-x 2 root root 4,0K mar 26 2012 rc3.d
lrwxrwxrwx 1 root root 21 mar 26 2012 resolv.conf -&amp;gt; ../rw/etc/resolv.conf
lrwxrwxrwx 1 root root 16 mar 26 2012 shadow -&amp;gt; ../rw/etc/shadow
drwxrwxr-x 2 root root 4,0K mar 26 2012 udhcpc
drwxrwxrwx 2 root root 4,0K mar 26 2012 usbmgr
-rw-rw-rw- 1 root root 8 mar 26 2012 version
root@kali:~/Projects/tg582n/_dump.bin.extracted/squashfs-root/etc#
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;
`passwd` file is a link to another file in the `/rw` directory that, right now, is empty. How that file is generated during every boot? What script is in charge of managing it? We need to find the answers...
## Hunting for the system users
Poking around in `/etc` directory can be useful because, in the end, this is a standard Linux based system and something in that directory must exist that will reveal us what are the allowed users to the system.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;root@kali:~/Projects/tg582n/_dump.bin.extracted/squashfs-root/etc# tree
.
├── advancedservices.conf
├── autoconf.conf
├── autoip.conf
├── config
│   ├── secrets.tdb -&amp;gt; /rw/etc/secrets.tdb
│   ├── smb.conf -&amp;gt; /rw/etc/smb.conf
│   └── smbpasswd -&amp;gt; /rw/etc/smbpasswd
├── fileprofiler.conf
├── fstab
├── fuse.conf
├── group -&amp;gt; ../rw/etc/group
├── gshadow -&amp;gt; ../rw/etc/gshadow
├── host.conf
├── init.d
│   ├── anti_spoofd
│   ├── autoipd
│   ├── checkd
│   ├── cifs
│   ├── clinkd
│   ├── cryptomount
│   ├── dropbear
│   ├── fseventd
│   ├── fuse
│   ├── initrandom
│   ├── jffs2contentcheck
│   ├── ledstatus
│   ├── linuxappl
│   ├── longops
│   ├── mbusd_util
│   ├── mocad
│   ├── monitoripd
│   ├── mud
│   ├── mvfs
│   ├── mvfspl
│   ├── network
│   ├── nlplugd
│   ├── no_hotplug_helper
│   ├── powermgr
│   ├── print_server
│   ├── pureftp
│   ├── rc
│   ├── rcS
│   ├── rcS.mountfs
│   ├── rcS.ro
│   ├── rssplugin
│   ├── samba
│   ├── stopload
│   ├── storagepl
│   ├── todd
│   ├── udhcpcd
│   ├── upnpavpl
│   ├── usb-host
│   ├── usb_storage
│   └── vfspl
├── inittab
├── mime.types
├── mtab -&amp;gt; ../proc/mounts
├── nsswitch.conf
├── passwd -&amp;gt; ../rw/etc/passwd
├── rc0.d
├── rc1.d
│   ├── K01mvfs -&amp;gt; ../init.d/mvfs
│   ├── S01jffs2contentcheck -&amp;gt; ../init.d/jffs2contentcheck
│   ├── S10no_hotplug_helper -&amp;gt; ../init.d/no_hotplug_helper
│   ├── S20network -&amp;gt; ../init.d/network
│   ├── S21vega -&amp;gt; ../init.d/vega
│   ├── S21wps -&amp;gt; ../init.d/wps
│   ├── S22linuxappl -&amp;gt; ../init.d/linuxappl
│   ├── S41fseventd -&amp;gt; ../init.d/fseventd
│   ├── S45storagepl -&amp;gt; ../init.d/storagepl
│   ├── S45vfspl -&amp;gt; /etc/init.d/vfspl
│   ├── S46mvfspl -&amp;gt; ../init.d/mvfspl
│   ├── S47checkd -&amp;gt; ../init.d/checkd
│   ├── S47cifs -&amp;gt; ../init.d/cifs
│   ├── S48todd -&amp;gt; ../init.d/todd
│   ├── S48upnpavpl -&amp;gt; ../init.d/upnpavpl
│   ├── S49rssplugin -&amp;gt; ../init.d/rssplugin
│   ├── S55fuse -&amp;gt; ../init.d/fuse
│   ├── S56mvfs -&amp;gt; ../init.d/mvfs
│   ├── S67stopload -&amp;gt; ../init.d/stopload
│   ├── S68su_intf -&amp;gt; ../init.d/su_intf
│   ├── S69la_intf -&amp;gt; ../init.d/la_intf
│   ├── S71nlplugd -&amp;gt; ../init.d/nlplugd
│   ├── S72udhcpcd -&amp;gt; ../init.d/udhcpcd
│   ├── S73monitoripd -&amp;gt; ../init.d/monitoripd
│   ├── S74anti_spoofd -&amp;gt; ../init.d/anti_spoofd
│   ├── S80dropbear -&amp;gt; ../init.d/dropbear
│   ├── S97mud -&amp;gt; ../init.d/mud
│   ├── S97usb-host -&amp;gt; ../init.d/usb-host
│   └── S99powermgr -&amp;gt; ../init.d/powermgr
├── rc2.d
├── rc3.d
│   ├── S01jffs2contentcheck -&amp;gt; ../init.d/jffs2contentcheck
│   ├── S10no_hotplug_helper -&amp;gt; ../init.d/no_hotplug_helper
│   ├── S20network -&amp;gt; ../init.d/network
│   ├── S21vega -&amp;gt; ../init.d/vega
│   ├── S22linuxappl -&amp;gt; ../init.d/linuxappl
│   ├── S47checkd -&amp;gt; ../init.d/checkd
│   ├── S67stopload -&amp;gt; ../init.d/stopload
│   ├── S71nlplugd -&amp;gt; ../init.d/nlplugd
│   ├── S72udhcpcd -&amp;gt; ../init.d/udhcpcd
│   ├── S73monitoripd -&amp;gt; ../init.d/monitoripd
│   └── S74anti_spoofd -&amp;gt; ../init.d/anti_spoofd
├── resolv.conf -&amp;gt; ../rw/etc/resolv.conf
├── shadow -&amp;gt; ../rw/etc/shadow
├── udhcpc
│   └── udhcpc.script
├── usbmgr
│   ├── class -&amp;gt; /var/usbmgr/class
│   ├── dextension
│   ├── host -&amp;gt; /var/usbmgr/host
│   ├── preload.conf
│   ├── storage
│   ├── umts_custom
│   ├── update_usbmgrconf
│   ├── usbledctrl
│   ├── usbmgr.conf -&amp;gt; /var/tmp/usbmgr.conf
│   ├── usbmgr.conf.ro
│   └── vendor -&amp;gt; /var/usbmgr/vendor
└── version&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
For what it seems, interesting files in `/etc` directory are symlinks to the relative ones in `/rw` and, for me, `rw` has something to do with `Read` and `Write` operations. Let&amp;#39;s search some evidence of this path in configuration files:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;root@kali:~/Projects/tg582n/_dump.bin.extracted/squashfs-root/etc# grep -ir rw
init.d/clinkd:CLINKCONF_DEST=/rw/etc/
init.d/clinkd: #CPE_P00075123:CJ:Change clink.conf to a rw location
init.d/usb_storage: # eb 3c 90, we&amp;rsquo;re definitely dealing with a FAT boot sector. Otherwise, we
init.d/usb_storage: SMBD_STATUS=0 # 0 means that cifs service is stopped (otherwise it is running)
init.d/jffs2contentcheck:# push down of dl partition content into /rw/dl
init.d/jffs2contentcheck: # New layout: (USERFS mounted on /rw)
init.d/jffs2contentcheck: # /dl &amp;ndash;&amp;gt; /rw/dl
init.d/jffs2contentcheck: if [ &amp;ldquo;&lt;code&gt;cat /proc/mounts | grep /dev/mtdblock0 | grep /rw&lt;/code&gt;&amp;rdquo; ]; then
init.d/jffs2contentcheck: [ -d /rw/etc ] || mkdir -m 775 /rw/etc
init.d/jffs2contentcheck: if [ ! -d /rw/dl ]; then
init.d/jffs2contentcheck: echo &amp;quot; Detected old jffs2 partition layout! Converting /rw to new layout&amp;quot;
init.d/jffs2contentcheck: mkdir -m 775 /rw/dl
init.d/jffs2contentcheck: for file in /rw/*; do
init.d/jffs2contentcheck: ([ &amp;ldquo;${file}&amp;rdquo; = &amp;ldquo;/rw/dl&amp;rdquo; ] || [ &amp;ldquo;${file}&amp;rdquo; = &amp;ldquo;/rw/etc&amp;rdquo; ]) &amp;amp;&amp;amp; continue
init.d/jffs2contentcheck: mv ${file} /rw/dl/
init.d/jffs2contentcheck: # /rw &amp;ndash;&amp;gt; /userfs/config-bank-X
init.d/jffs2contentcheck: # /dl &amp;ndash;&amp;gt; /rw/dl
init.d/jffs2contentcheck: # Set /rw correctly: since /rw is on rootfs which is read-only, we
init.d/jffs2contentcheck: mount -o bind $CONFDIR /rw
advancedservices.conf:HDTOOLSDIR=&amp;quot;/rw/disk&amp;quot;
advancedservices.conf:FLASHCONFIGDIR=&amp;quot;/rw/etc/&amp;quot;
mime.types:application/vnd.vectorworks&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
We found that`clinkd`, `jffs2contentcheck` and `advancedservices.conf` have something to do with the `/rw` directory. Let&amp;#39;s review these evidence.
- `clinkd`: in the comment section of the script: &amp;#34;*This is the init script for the Entropic clinkd daemon*&amp;#34;. I wasn&amp;#39;t able to find useful informations about this daemon.
- `advancedservices.conf`: nothing too much interesting here, only a small nudge to the fact that `/rw/etc` is the writable part of the flash.
- `jffs2contentcheck`: this is interesting, we found plenty of informations in this script. For better understand its purpose, this is the full source and, actually, it&amp;#39;s pretty well commented.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;#!/bin/sh&lt;/p&gt;
&lt;h4 id=""&gt;
&lt;/h4&gt;&lt;h1 id="this-script-checks-and-converts-the-layout-of-the-writable-partition-to-its"&gt;This script checks and converts the layout of the writable partition to its
&lt;/h1&gt;&lt;h1 id="latest-version"&gt;latest version.
&lt;/h1&gt;&lt;h1 id=""&gt;
&lt;/h1&gt;&lt;h1 id="changelog"&gt;Changelog:
&lt;/h1&gt;&lt;h1 id="-744--811"&gt;* 7.4.4 &amp;gt; 8.1.1:
&lt;/h1&gt;&lt;h1 id="push-down-of-dl-partition-content-into-rwdl"&gt;push down of dl partition content into /rw/dl
&lt;/h1&gt;&lt;h1 id="steven-aerts--20080312"&gt;[Steven Aerts &amp;ndash; 2008/03/12]
&lt;/h1&gt;&lt;h4 id=""&gt;
&lt;/h4&gt;&lt;p&gt;. /etc/autoconf.conf&lt;/p&gt;
&lt;p&gt;start () {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Verify 7.4.4 to 8.1.1 userfs migration
# Old layout: (USERFS mounted on /dl)
# USERFS/user.ini
# USERFS/etc/...
# USERFS/tls/...
# New layout: (USERFS mounted on /rw)
# USERFS/etc/...
# USERFS/dl/user.ini
# USERFS/dl/tls/...
# /dl --&amp;gt; /rw/dl
if [ &amp;quot;`cat /proc/mounts | grep /dev/mtdblock0 | grep /rw`&amp;quot; ]; then
[ -d /rw/etc ] || mkdir -m 775 /rw/etc
if [ ! -d /rw/dl ]; then
echo &amp;quot; Detected old jffs2 partition layout! Converting /rw to new layout&amp;quot;
mkdir -m 775 /rw/dl
for file in /rw/*; do
([ &amp;quot;${file}&amp;quot; = &amp;quot;/rw/dl&amp;quot; ] || [ &amp;quot;${file}&amp;quot; = &amp;quot;/rw/etc&amp;quot; ]) &amp;amp;&amp;amp; continue
mv ${file} /rw/dl/
done
fi
fi
# Migrate to dual bank layout
# New layout: (USERFS mounted on /userfs)
# USERFS/config-bank-X/etc/...
# USERFS/config-bank-X/dl/...
# /rw --&amp;gt; /userfs/config-bank-X
# /dl --&amp;gt; /rw/dl
# Determine booted bank from command line
BOOTID=$(sed -n &amp;quot;s/.*btab_bootid=\([0-9]\+\).*/\1/p&amp;quot; /proc/cmdline)
# If BOOTID is empty, set it to a certain value (single-bank case)
[ -z &amp;quot;$BOOTID&amp;quot; ] &amp;amp;&amp;amp; BOOTID=999
CONFDIR=&amp;quot;/userfs/config-bank-$BOOTID&amp;quot;
# Create a config directory for the booted bank if it does not yet exist
[ ! -d $CONFDIR ] &amp;amp;&amp;amp; mkdir $CONFDIR
# Set /rw correctly: since /rw is on rootfs which is read-only, we
# cannot use a symlink. However, mount supports the bind option which
# essentially does the same.
mount -o bind $CONFDIR /rw
# If there are any files/directories in /userfs (config-bank-X
# directories excluding), move them to the config directory of the
# booted bank. This indicates a first boot from BLI.
for i in $(ls /userfs | grep -v &amp;quot;^config-bank-*&amp;quot; | grep -v &amp;quot;^common$&amp;quot;); do
mv /userfs/$i $CONFDIR
done
# If the config directory is still empty, copy the configuration
# from another bank to allow a 'correct' boot. This can happen when
# you upgrade an rbi with the bootloader.
# NOTE: there is no guarantee that this configuration will work, but
# it's better to have something.
if [ -z &amp;quot;$(ls $CONFDIR | grep -v &amp;quot;^version$&amp;quot; 2&amp;gt;/dev/null)&amp;quot; -a -x /usr/bin/copyconfig ]; then
/usr/bin/copyconfig &amp;quot;lastboot&amp;quot; $BOOTID
fi
# Set the 'lastboot' symlink to the current configuration
rm -f /userfs/config-bank-lastboot
ln -sf $CONFDIR /userfs/config-bank-lastboot
# Copy the version file from /etc to /userfs/config-bank-X
if [ -f /etc/version ]; then
cp /etc/version $CONFDIR
else
echo &amp;quot;Unknown&amp;quot; &amp;gt; $CONFDIR/version
fi
# Create a common userfs directory
[ ! -d /userfs/common ] &amp;amp;&amp;amp; mkdir /userfs/common
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;case $1 in
start)
start
;;
stop)
;;
restart)
;;
*)
echo &amp;ldquo;Usage $0 [start|stop|restart]&amp;rdquo;
exit 1
;;
esac&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
What&amp;#39;s [JFFS2](https://en.wikipedia.org/wiki/JFFS2) filesystem?
&amp;gt; JFFS2 (Journaled Flash File System v2) is a file system designed for use on Flash devices such as those commonly found in embedded systems. Unlike some other file systems which may be stored on the Flash device and then copied into RAM during boot (i.e. ramdisk) JFFS2 actually resides on the Flash device and allows the user to read/write data to Flash. This is particularly useful in embedded devices that wish to save some persistent data between reboots. [[cit](http://processors.wiki.ti.com/index.php/AM335x_JFFS2_Support_Guide#)]
We finally found where the persistent informations are saved. Coming back to the binwalk analysis, I remember many signature related to JFFS2 filesystem. Let&amp;#39;s review the evidences extracted:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;root@kali:~/Projects/tg582n/_dump.bin.extracted# tree jff*
jffs2-root
└── fs_1
├── common
│   └── flash_image_fii
├── config-bank-999
│   ├── dl
│   │   ├── persistent.cnf
│   │   ├── phy.conf
│   │   ├── seed.dat
│   │   ├── stsZWEADQ8.CM0.upg
│   │   ├── tls
│   │   │   ├── cert0001.pem
│   │   │   └── pkey0001.pem
│   │   ├── user.ini
│   │   └── xdsl.inf
│   ├── etc
│   │   ├── group
│   │   ├── gshadow
│   │   ├── passwd
│   │   ├── resolv.conf
│   │   ├── secrets.tdb
│   │   ├── shadow
│   │   ├── smb.conf
│   │   └── smbpasswd
│   └── version
└── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
jffs2-root-0
└── fs_1
├── common
│   └── flash_image_fii
├── config-bank-999
│   ├── dl
│   │   ├── persistent.cnf
│   │   ├── phy.conf
│   │   ├── seed.dat
│   │   ├── stsZWEADQ8.CM0.upg
│   │   ├── tls
│   │   │   ├── cert0001.pem
│   │   │   └── pkey0001.pem
│   │   ├── user.ini
│   │   └── xdsl.inf
│   ├── etc
│   │   ├── group
│   │   ├── gshadow
│   │   ├── passwd
│   │   ├── resolv.conf
│   │   ├── secrets.tdb
│   │   ├── shadow
│   │   ├── smb.conf
│   │   └── smbpasswd
│   └── version
└── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
jffs2-root-1
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── phy.conf
├── secrets.tdb
├── smb.conf
├── smbpasswd
├── stsZWEADQ8.CM0.upg
├── user.ini
└── xdsl.inf
jffs2-root-10
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-11
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-12
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-13
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-14
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-15
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-16
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-17
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-18
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-19
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-2
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── secrets.tdb
├── smb.conf
├── smbpasswd
├── stsZWEADQ8.CM0.upg
├── user.ini
└── xdsl.inf
jffs2-root-20
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-21
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-22
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-23
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-24
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
└── smbpasswd
jffs2-root-25
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
└── smbpasswd
jffs2-root-26
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
└── smbpasswd
jffs2-root-27
└── fs_1
├── passwd
└── smbpasswd
jffs2-root-28
└── fs_1
├── passwd
└── smbpasswd
jffs2-root-29
└── fs_1
└── smbpasswd
jffs2-root-3
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── secrets.tdb
├── smb.conf
├── smbpasswd
├── user.ini
└── xdsl.inf
jffs2-root-4
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── secrets.tdb
├── smbpasswd
├── user.ini
└── xdsl.inf
jffs2-root-5
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
├── user.ini
└── xdsl.inf
jffs2-root-6
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
├── user.ini
└── xdsl.inf
jffs2-root-7
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
├── user.ini
└── xdsl.inf
jffs2-root-8
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini
jffs2-root-9
└── fs_1
├── config-bank-lastboot -&amp;gt; /userfs/config-bank-999
├── group
├── passwd
├── persistent.cnf
├── smbpasswd
└── user.ini&lt;/p&gt;
&lt;p&gt;41 directories, 210 files&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
Honestly I don&amp;#39;t know why there are so much copies of same files but, definitely, we found what we were looking for: not only the `passwd` file but also certificates with private keys, user configurations, xdsl line configurations, etc.
Let&amp;#39;s try to understand if there are any differences between files inside that directories, so we can narrow our analysis. With a basic bash scripting knowledge, we can use `md5sum` to find if files are the same. Turns out that almost every file are copies and the only variable is `user.ini`. Also, the `.upg` file appears to be the same of `smbpasswd`.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;group b6645876780362adfefe6ae7aa2aa970
passwd ccfbeda0bfe6a969d9f3e95284e450be
persistent.cnf 0169902625104a21be24f44df679d610
phy.conf c176b13932e5bf01930a066491877986
secrets.tdb cbe77f45cae8dad41cb9bef73ed69ed6
smb.conf 7c6ed2fab7571c3441d3af6740f9d067
smbpasswd d41d8cd98f00b204e9800998ecf8427e
stsZWEADQ8.CM0.upg d41d8cd98f00b204e9800998ecf8427e
user.ini 080b575f72aa410d0d2606ed9f152c18
user.ini 1b37b14685d303d192c80e5e8c3e68c7
user.ini 1d57ab52d6fa5d4d61cf6f520ac62b29
user.ini 2113deb10fd3cc6e5e5d5fc44489ee13
user.ini 2fbe85cc5305473ad68ae9b842134696
user.ini 3a4860416befea32f5a6952f75c1073e
user.ini 4388cd21843a0e1dbc7ec8b9d6b0fe81
user.ini 59499065a1243c0fd0bc3aec77eb5052
user.ini 6281deec4ac9389b797afc4873b9a90a
user.ini 6400c4bc913e682e32e055d262c058d4
user.ini 8165fea871781c7320bd6ef3b201c90f
user.ini 8504dfd01106e4f2e2a21c6e7460964e
user.ini 919573ff12d4eabf968a6dfd97a7d616
user.ini c4f70675bc732dd93fc8bb9c9219fb74
user.ini cab37a7859e4cb319aa1684f9fbee277
user.ini e9930518fb8db6670f14af642e177083
xdsl.inf 25daad3d9e60b45043a70c4ab7d3b1c6&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
Let&amp;#39;s analyze them:
`group`: standard file, the same you can find on all *nix systems but with interesting groups.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;SuperUser::101:
TechnicalSupport::102:
Administrator::103:
WebsevUser::104:
LAN_Admin::105:
PowerUser::106:
User::107:
WAN_Admin::108:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
`passwd`: the file we were looking for. This file will be slightly modified during boot because root access is somehow disabled but at least we found two users: `Administrator` and `tech` with relative hash.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;root::0:0:Super User:/:/bin/sh
nobody:&lt;em&gt;:1:1:nobody:/:/bin/sh
mvfs:&lt;/em&gt;:499:1::/var/mvfs:/bin/sh
Administrator:ANpAYtow5vx0U:500:103:Linux User:(null):/bin/sh
tech:RB6zAiLmCT4zM:501:102:Linux User:(null):/bin/sh&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
If you search on Google, turns out that the hash `ANpAYtow5vx0U`was generated by the command `mkpasswd` and [here](https://www.seancassidy.me/etc/passwords.txt) we can read that:
&amp;gt; If your password is on this list, it is not secure. It was generated by using the program &amp;#39;*mkpasswd&amp;#39;* and then not typing anything. It turns out that &amp;#39;mkpasswd&amp;#39; doesn&amp;#39;t make passwords, it makes password hashes. If you enter a blank password, it generates one of 4096 possible passwords.
So, Administrator user has a simple **blank** password, I didn&amp;#39;t find anything similar with the hash of the tech user. For this user I started a simple crack session with `john`, and without any fancy cracking rig or powerful graphic video card, after an affordable cracking time (~ 2days) I managed to crack the password: it appears to be `55058391`.
![](/images/2019/01/image-22.png)
`secrets.tdb`: related to Samba services, it stores passwords in clear text. This file can be opened with the `tdbdump`:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;{
key(23) = &amp;ldquo;SECRETS/SID/TECHNICOLOR&amp;rdquo;
data(68) = &amp;ldquo;\01\04\00\00\00\00\00\05\00\00\00\15\89+\B5\E1jD\15P\1A\92\F03\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00&amp;rdquo;
}
{
key(17) = &amp;ldquo;INFO/random_seed\00&amp;rdquo;
data(4) = &amp;ldquo;y\04\00\00&amp;rdquo;
}&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
`user.ini`: router clear text configuration file.
There are some other files but, for now, we have enough to start.
## Accessing the device...*in some way*
We found that the Administrator user has blank password. We can now login via console access. Tech user access is somehow disabled.
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="password-"&gt;Username : Administrator
Password :
&lt;/h2&gt;&lt;pre&gt;&lt;code&gt; ______ Technicolor TG582n
___/_____/\
/ /\\ 8.C.M.0
_____/__ / \\
_/ /\_____/___ \ Copyright (c) 1999-2012, Technicolor
// / \ /\ \
_______//_______/ \ / _\/______
/ / \ \ / / / /\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;/ / \ \ / / / / &lt;em&gt;_&lt;/em&gt;
/ / / _&lt;/strong&gt;&lt;em&gt;&lt;strong&gt;&lt;em&gt;/ / / / / /&lt;br&gt;
/&lt;/em&gt;/&lt;/strong&gt;&lt;/em&gt;&lt;em&gt;&lt;strong&gt;/&lt;/strong&gt;&lt;/em&gt;&lt;em&gt;&lt;strong&gt;&lt;strong&gt;&lt;em&gt;&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;/ /___&lt;strong&gt;&lt;em&gt;&lt;strong&gt;/ /&lt;/strong&gt;&lt;/em&gt;/ \
\ \ \ ___________ \ \ \ \ \ /
_\ \ / /\ \ \ \ _&lt;/strong&gt;/
\ / / \ \ \ \ /
_&lt;/strong&gt;&lt;/strong&gt;/ / \ \ _&lt;/strong&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/em&gt;/
/&lt;/strong&gt;&lt;/strong&gt;&lt;/em&gt;&lt;em&gt;&lt;strong&gt;&lt;strong&gt;/ \ \ /
\ _____ \ /__&lt;em&gt;&lt;strong&gt;/
\ / /\ \ /&lt;/strong&gt;&lt;/em&gt;/ F.D.C. FW 14
/&lt;/strong&gt;&lt;/strong&gt;/ \ \ /
\ \ /&lt;/em&gt;&lt;strong&gt;/
_&lt;/strong&gt;_/&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;{Administrator}=&amp;gt;
contentsharing firewall printersharing &lt;br&gt;
pwr service connection &lt;br&gt;
cwmp dhcp dns &lt;br&gt;
download dsd dyndns &lt;br&gt;
eth atm config &lt;br&gt;
debug env expr &lt;br&gt;
grp hostmgr ids &lt;br&gt;
igmp interface ip &lt;br&gt;
ipqos label language &lt;br&gt;
mbus memm mlp &lt;br&gt;
mobile nat ppp &lt;br&gt;
pptp ptrace script &lt;br&gt;
sntp software statecheck &lt;br&gt;
syslog system tls &lt;br&gt;
{Administrator}=&amp;gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
I spent a lot of time poking around in this weird restricted shell. I wasn&amp;#39;t able to escape to our beloved Busybox that I know is running below. No matter what I tried, I always ended up in this jail I could not escape. It seems to manage everything from the console access.
To confirm this theory, I found this old post:
![](/images/2019/02/image.png)
And suddenly I remembered this two sneaky files laying in the `/nmon` directory.
![](/images/2019/02/image-2.png)
I&amp;#39;m quite sure this program is run at boot time and, basically, take the control of the entire router. This can now be confirmed in the boot log above:
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;linux application start &amp;hellip;
wait for linux_appl to initialize (1)
wait for linux_appl to initialize (2)
************* ERROR RECORD *************
000000:00:00.000000
Application NMON started after POWERON.
****************** END *****************
wait for linux_appl to initialize (3)
appl_init: BUILD VERIFIED!
wait for linux_appl to initialize (4)
[SS EMUL] ERR: opening config file /active/ss.conf failed
End of initialisation
wait for linux_appl to initialize (5)&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
And this is the script that, at boot time, runs the `linux_appl.exe`
&lt;/code&gt;&lt;/pre&gt;&lt;h1 id=""&gt;
&lt;/h1&gt;&lt;p&gt;#/etc/init.d/linuxappl&lt;/p&gt;
&lt;h1 id=""&gt;
&lt;/h1&gt;&lt;p&gt;#!/bin/sh&lt;/p&gt;
&lt;p&gt;. /etc/init.d/mbusd_util&lt;/p&gt;
&lt;p&gt;case $1 in
start)
TELLER=0
# linux application configuration
/bin/echo &amp;ldquo;linux application start &amp;hellip;&amp;rdquo;
rm -f /var/run/linux_appl
rm -f /var/run/init_finished
mbusd_set_loadapp
../../nmon/linux_appl.exe /dev/nmon/nmontrace /dev/nmon/nmonerr /archive/ &amp;amp;
while [ ! -f /var/run/linux_appl ]
do
TELLER=&lt;code&gt;expr ${TELLER} + 1&lt;/code&gt;
echo &amp;ldquo;wait for linux_appl to initialize (${TELLER})&amp;rdquo;
sleep 1;
done
;;
stop)
killall -9 linux_appl
;;
*)&lt;/p&gt;
&lt;p&gt;esac&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;
### Next steps
This ends up this phase of my journey. Honestly, I was (*am*) not prepared to impact in a so restricted and particular environment. My next steps will be to look the router from a network point of view, analyzing it while it&amp;#39;s *up &amp;amp; running,* trying to find information within the services it runs and offers.
I hope you will find this post useful and if you have any hints or ideas to help me, please drop me a note.
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Pony stealer: a malware analysis - The sample analysis - Part three</title><link>https://blog.kartone.ninja/pony-stealer-a-malware-analysis-the-sample-analysis-part-three/</link><pubDate>Mon, 10 Sep 2018 07:30:00 +0000</pubDate><guid>https://blog.kartone.ninja/pony-stealer-a-malware-analysis-the-sample-analysis-part-three/</guid><description>&lt;p&gt;After the first two parts &lt;a class="link" href="https://blog.kartone.ninja/pony-stealer-malware-analysis/" &gt;here&lt;/a&gt; and &lt;a class="link" href="https://blog.kartone.ninja/pony-stealer-a-malware-analysis-analyzing-the-sample/" &gt;here&lt;/a&gt;, we can move forward giving the sample a run inside a disassembler to look what&amp;rsquo;s inside and, eventually, into a debugger to see it live.&lt;/p&gt;
&lt;p&gt;IDA has some difficulties to analyze the sample due to the facts it heavily uses anti-disassembly trick:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-6.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Note that the conditional jump to &lt;code&gt;41062E&lt;/code&gt; never gonna happens. We can patch those bytes &lt;code&gt;\xF8\x72\x01&lt;/code&gt; with &lt;code&gt;NOP&lt;/code&gt; instruction or leave them alone knowing the fact that IDA can be fooled during analysis. Also at &lt;code&gt;41062F&lt;/code&gt; the sample delays its execution, invoking &lt;code&gt;GetTickCount&lt;/code&gt; function and dividing the remainder of the &lt;code&gt;DIV&lt;/code&gt; instruction by a predefined constant. So until the &lt;code&gt;CMP&lt;/code&gt; instruction is satisfied it will run this bunch of code a pseudo-random number of times. It appears that this technique can trick some antivirus heuristic controls.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-7.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;After condition is verified, the flow reaches the &lt;code&gt;CALL&lt;/code&gt; instruction at &lt;code&gt;4105c3&lt;/code&gt;, we see another anti-disassembly technique, the misaligned &lt;code&gt;PUSH&lt;/code&gt; instruction.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-8.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Clearly the misaligned &lt;code&gt;PUSH&lt;/code&gt; at &lt;code&gt;4105c7&lt;/code&gt; is there to fool the disassembler and we need to fix it if we want to have a better look on that piece of code. By defining manually that byte at &lt;code&gt;4105d0&lt;/code&gt;, IDA can now better analyze the code:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-9.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Now it&amp;rsquo;s clear what this piece of code does: it pushes the address of the function at &lt;code&gt;4105a2&lt;/code&gt; onto the stack. This pointer will be the argument of &lt;code&gt;SetUnhandledExceptionFilter&lt;/code&gt; function that, in the end, will exit from the process in case of unhandled exception.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-13.png"
loading="lazy"
&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-10.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s focus on what happens at address &lt;code&gt;410508&lt;/code&gt;, because it&amp;rsquo;s where the fun starts:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-15.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;After some studies I tried to interpret that code and the results are shown below.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-14.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Basically malware is starting its activities: first it loads libraries with the &lt;code&gt;OleInitialize&lt;/code&gt; and &lt;code&gt;LoadLibraries&lt;/code&gt; calls, after it fires up a delayer routine that, in malware intentions, will fool the heuristic controls of Kaspersky Antivirus. After that it enable some required privileges with the fourth call:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-16.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;This routine will cycle through and enable all these privileges:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-17.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;And after that it tries to get if the process is running within &lt;code&gt;LocalSystem&lt;/code&gt; or not. In both cases it will impersonate or the &lt;code&gt;LocalSystemUser&lt;/code&gt; or the &lt;code&gt;LocalUser&lt;/code&gt; using the API call to &lt;code&gt;GetUserNameA&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the next session we&amp;rsquo;ll go deeper into the analysis trying to better understand its codebase.&lt;/p&gt;</description></item><item><title>Pony stealer: a malware analysis - The sample dry run - Part two</title><link>https://blog.kartone.ninja/pony-stealer-a-malware-analysis-analyzing-the-sample/</link><pubDate>Fri, 03 Aug 2018 07:00:00 +0000</pubDate><guid>https://blog.kartone.ninja/pony-stealer-a-malware-analysis-analyzing-the-sample/</guid><description>&lt;p&gt;After we were able to unpack the sample like we did in the &lt;a class="link" href="https://blog.kartone.ninja/pony-stealer-malware-analysis/" &gt;previous&lt;/a&gt; post, it&amp;rsquo;s time to understand what the malware is intended to do. The very first thing that I normally do is to give the sample a dry run inside a dedicated virtual machine, just to observe its behavior and monitoring its API calls. These calls can be monitored with a little tool called ApiLogger - that can be found &lt;a class="link" href="https://www.aldeid.com/wiki/SysAnalyzer/ApiLogger" target="_blank" rel="noopener"
&gt;here&lt;/a&gt; and it&amp;rsquo;s automatically installed by the &lt;a class="link" href="https://github.com/fireeye/flare-vm" target="_blank" rel="noopener"
&gt;Flare-vm&lt;/a&gt; script.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The API logger works by injecting a DLL into the target process. Once loaded, the DLL will insert a series of detours style hooks into specific API calls. When these API are accessed by any code in the process, they will trigger a notification message which gets sent to the main interface.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It&amp;rsquo;s clear that malware tries to steal informations (probably credentials) of various software via calls to &lt;strong&gt;RegOpenKeyA&lt;/strong&gt; and &lt;strong&gt;RegOpenKeyExA:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;And at the end of the run, it tries to connect to the domain &lt;strong&gt;singatradeing.com&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-1.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can catch this connection with another great tool from FireEye, &lt;strong&gt;&lt;a class="link" href="https://github.com/fireeye/flare-fakenet-ng" target="_blank" rel="noopener"
&gt;FakeNet-NG&lt;/a&gt;&lt;/strong&gt; that will capture and fake responses to all the queries DNS and HTTP  requests, saving all activities into a pcap file that could be analyzed with Wireshark:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-2.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can see that the malware resolved the domain name &lt;strong&gt;singatradeing.com&lt;/strong&gt; with a query DNS (that is faked by FakeNet-NG):&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-3.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;And sent an http GET request to: &lt;strong&gt;&lt;a class="link" href="http://singatradeing.com/espnphp/coreserver/shit.exe" target="_blank" rel="noopener"
&gt;http://singatradeing.com/espnphp/coreserver/shit.exe&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-4.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Our fake response served an executable file that was run by the malware:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/08/image-5.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;After that, the malware deleted itself. For this reason, remember to make a copy of the sample executable.&lt;/p&gt;
&lt;p&gt;I wasn&amp;rsquo;t able to download the real executable (shit.exe) but I&amp;rsquo;m sure it will be easy to find it.&lt;/p&gt;
&lt;p&gt;More informations related to that domain can be found &lt;a class="link" href="https://www.virustotal.com/en/domain/SINGATRADEING.COM/information/" target="_blank" rel="noopener"
&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="recap"&gt;Recap
&lt;/h3&gt;&lt;p&gt;The malware sample, when it runs, tries to steal credentials from the registry keys, tries to download another executable and run it, deleting itself at the end.&lt;/p&gt;</description></item><item><title>Pony stealer: a malware analysis - Unpacking the sample - Part one</title><link>https://blog.kartone.ninja/pony-stealer-malware-analysis/</link><pubDate>Mon, 23 Jul 2018 07:00:00 +0000</pubDate><guid>https://blog.kartone.ninja/pony-stealer-malware-analysis/</guid><description>&lt;h1 id=""&gt;
&lt;/h1&gt;&lt;p&gt;During my day by day job, I had the chance to came across a mail that was blocked by an antispam platform. Attached to this mail there was a sample recognized as a variant of &lt;a class="link" href="https://blog.malwarebytes.com/detections/spyware-pony/" target="_blank" rel="noopener"
&gt;Pony Stealer malware&lt;/a&gt;. Since I&amp;rsquo;ve been greatly interested into malware analysis in the last few months, I thought it would be fun, and also a useful exercise, to apply all the notions I&amp;rsquo;ve been reading so far and writing this post, maybe, would help me in fixing methodologies and concepts. I hope this will be a two parts blog post: during this first part I will focus on unpacking the malware, during the second one I&amp;rsquo;ll try to analyze its real behavior. Let&amp;rsquo;s the journey begin.&lt;/p&gt;
&lt;h2 id="noob-alert"&gt;Noob alert
&lt;/h2&gt;&lt;p&gt;First things first: I&amp;rsquo;m no expert at all. This is my first experience in reversing malware - and also in blogging something - and so expect a lot of shady things and confused assumptions. Learning something new is always a good idea and I hope that digging into malware analysis will allow me to glue together some skills that I&amp;rsquo;m trying to learn in the last couple of  years. Also, do not rely on the memory addresses in the screenshots. As this post was written during various sessions, memory addresses changed every time due to operating system memory protections (ASLR).&lt;/p&gt;
&lt;h2 id="lab-setup"&gt;Lab setup
&lt;/h2&gt;&lt;p&gt;You can find great tutorials online on how to setup a professional and secure lab to test all malicious sample you get. I&amp;rsquo;d like to point you out to these useful resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/" target="_blank" rel="noopener"
&gt;Microsoft Windows 7 and 10 images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/fireeye/flare-vm" target="_blank" rel="noopener"
&gt;Flare-vm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://oalabs.openanalysis.net/2018/07/16/oalabs_malware_analysis_virtual_machine/" target="_blank" rel="noopener"
&gt;Malware Analysis Virtual Machine&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="running-the-sample-into-online-sandbox"&gt;Running the sample into online sandbox
&lt;/h2&gt;&lt;p&gt;Since, right now, I don&amp;rsquo;t have a working setup of &lt;a class="link" href="https://cuckoosandbox.org" target="_blank" rel="noopener"
&gt;Cuckoo sandbox&lt;/a&gt; on my behalf, the very first thing I did was uploading the sample into a freely usable sandbox online with these results: &lt;a class="link" href="http://tinyurl.com/y9gspzmt" target="_blank" rel="noopener"
&gt;http://tinyurl.com/y9gspzmt&lt;/a&gt;. As you can see, it labels the sample as a variant of the &lt;em&gt;VBObfus.g&lt;/em&gt; family. I didn&amp;rsquo;t find  a lot of informations about this malware family, but dynamic analysis shows me very few indicators:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No evidence of malware activity into screenshot.&lt;/li&gt;
&lt;li&gt;No network activity.&lt;/li&gt;
&lt;li&gt;Every string is almost obfuscated.&lt;/li&gt;
&lt;li&gt;No extracted files.&lt;/li&gt;
&lt;li&gt;No evidence of process injection.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Important to note, although no clear evidences, the sample is classified as malicious with threat level as 71/100. Pretty strange, uh?&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://www.hybrid-analysis.com" target="_blank" rel="noopener"
&gt;Hybrid Analysis&lt;/a&gt; has this great feature: if you click on the sample filename, in this case &lt;strong&gt;SKMBT_C36018060720040_pdf.exe&lt;/strong&gt;*,* it shows a bunch of useful informations such as API calls used by the executable, registry keys it gets and/or sets during its runtime, filesystem activity, handles opened to files, operating system modules and other kind of libraries it uses. With all these informations we should have a proper level of confidence of what happens during the sandbox run. Let&amp;rsquo;s dig into some of them.&lt;/p&gt;
&lt;p&gt;First thing I looked at, was the activity on the filesystem:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image.jpeg"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;No files saved and the infamous msvbvm60.dll caught my attention, but we will deal with this later. Nothing too much interesting into registry section too:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-1.jpeg"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a possibility to filter the operations (Query, Open, Write and Delete) but I didn&amp;rsquo;t find anything related to write or delete operations.&lt;/p&gt;
&lt;p&gt;The most interesting section is the API calls section. To understand the malware behavior during its run inside the sandbox, it&amp;rsquo;s necessary to analyze what API this sample calls. Following &lt;a class="link" href="https://www.symantec.com/connect/articles/windows-anti-debug-reference" target="_blank" rel="noopener"
&gt;this&lt;/a&gt; and &lt;a class="link" href="https://bitbucket.org/NtQuery/scyllahide/downloads/ScyllaHide.pdf" target="_blank" rel="noopener"
&gt;this&lt;/a&gt; useful resources, I started checking API calls, trying to find any evidence of anti-debug or anti-vm techniques, mainly because there&amp;rsquo;s no evidence of process injection and nowadays process injection is a very, very common technique. After checking all API anti-debug calls found in documentation I was clearly missing something because I wasn&amp;rsquo;t able to find any of them. So it&amp;rsquo;s time to give it a run into my lab and observe its behavior.&lt;/p&gt;
&lt;h2 id="static-analysis"&gt;Static analysis
&lt;/h2&gt;&lt;p&gt;Before give it a run, let&amp;rsquo;s check with some basic tools how&amp;rsquo;s the file is built:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-2.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;So, really we&amp;rsquo;re dealing with a VisualBasic 5/6 executable file.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-3.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s dig into more details with the executable:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-4.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;With this great tool we can find some initial informations:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;File Version Info Size=1548 -&amp;gt; 060Ch&lt;br&gt;
Translations : 040904B0     Language : English (U.S.)  -  ( 0 4 0 9 )&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;CompanyName  =  NIrSOft&lt;br&gt;
FileDescription  =  ELEctrum&lt;br&gt;
FileVersion  =  6.02&lt;br&gt;
InternalName  =  Bulbotuber&lt;br&gt;
LegalCopyright  =  LAVasoft&lt;br&gt;
LegalTradeMarks  =  THE ERAser PROject&lt;br&gt;
OriginalFilename  =  Bulbotuber.exe&lt;br&gt;
ProductName  =  ASUs&lt;br&gt;
ProductVersion  =  6.02&lt;br&gt;
Comments  =  Pwa, INA.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Don&amp;rsquo;t know how useful these informations are but, anyway, it&amp;rsquo;s always better to have informations rather than nothing. Assumed that it&amp;rsquo;s a VB5/6 executable file and I don&amp;rsquo;t know how to deal with it inside IDAPro, my next action will be to run it inside my Analysis VM, with the intent to understand better its behavior.&lt;/p&gt;
&lt;h2 id="dynamic-analysis"&gt;Dynamic analysis
&lt;/h2&gt;&lt;p&gt;Interestingly it seems to me that, after some sort of unpacking in memory, there is clearly a process injection:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/pexplorer.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Apparently there must be in place some sort of anti-debug and/or anti-vm tricks. Easily enough in x32dbg there is a life-saving plugin, named ScyllaHide, that is capable of doing some black magic to hide the debugger from malware. We can avoid the process crashing during its run inside the debugger.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-8.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can observe that the sample creates another process with the same name - a copy of itself - and this is typically an indication of the &lt;strong&gt;&lt;a class="link" href="http://www.autosectools.com/Process-Hollowing.pdf" target="_blank" rel="noopener"
&gt;process hollowing&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I won&amp;rsquo;t dig into describing the process injection because there are some great guys that have created very complete and clear tutorials on how to approach this technique. I can suggest &lt;a class="link" href="https://oalabs.openanalysis.net" target="_blank" rel="noopener"
&gt;this&lt;/a&gt; site maintained by this great guy: &lt;a class="link" href="https://twitter.com/herrcore" target="_blank" rel="noopener"
&gt;Sergey&lt;/a&gt; and also his Youtube channel &lt;a class="link" href="https://www.youtube.com/channel/UC--DwaiMV-jtO-6EvmKOnqg" target="_blank" rel="noopener"
&gt;here&lt;/a&gt;. I strongly suggest to follow all of his videos and tutorials: they are a great way to learn malware analysis and unpacking.&lt;/p&gt;
&lt;h2 id="unpacking-the-malware"&gt;Unpacking the malware
&lt;/h2&gt;&lt;p&gt;To unpack the malware we&amp;rsquo;ll focus mainly on these three API calls:&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.microsoft.com/it-it/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createprocessa" target="_blank" rel="noopener"
&gt;kernel32.CreateProcessW&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://undocumented.ntinternals.net" target="_blank" rel="noopener"
&gt;ntdll.NtWriteVirtualMemory&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-resumethread" target="_blank" rel="noopener"
&gt;ntdll.NtResumeThread&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="new-process-creation"&gt;New process creation
&lt;/h3&gt;&lt;p&gt;First API call to breakpoint into debugger is kernel32.CreateProcessW, that &lt;em&gt;creates a new process and its primary thread (cit. Microsoft)&lt;/em&gt;. We&amp;rsquo;re interested in its syntax:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;BOOL CreateProcessA(
LPCSTR lpApplicationName,
LPSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCSTR lpCurrentDirectory,
LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And more interestingly, its structure on the stack when its called:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-9.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;In accordance with the calling convention the function parameters are pushed on the stack in reverse order.  At address &lt;strong&gt;0x0018F460&lt;/strong&gt; there&amp;rsquo;s the function fifth parameter &lt;em&gt;dwCreationFlags,&lt;/em&gt; with the value of &lt;strong&gt;0x00000004.&lt;/strong&gt; This value means &lt;strong&gt;CREATE_SUSPENDED;&lt;/strong&gt; we have reached the start of the hollowing process: a new copy of the process has been created in suspended mode.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-10.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;We can confirm its PID &lt;strong&gt;2660,&lt;/strong&gt; running the function CreateProcessW until it returns and checking in memory dump the value of the first parameter pushed on the stack at address &lt;strong&gt;0x0018F470&lt;/strong&gt; with the value of &lt;strong&gt;0x0643008C:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-11.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;The new process PID is at address &lt;strong&gt;0x06430094&lt;/strong&gt;: &lt;strong&gt;0x0A64&lt;/strong&gt; that translate into decimal in &lt;strong&gt;2660.&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="running-the-newly-created-process"&gt;Running the newly created process
&lt;/h3&gt;&lt;p&gt;We won&amp;rsquo;t bother too much with &lt;strong&gt;ntResumeThread&lt;/strong&gt; API call. Just note that when you reach breakpoint on this call, you know that the malware is ready to run itself (the new copy of itself actually) and, for this reason, you need to be very caution. Just don&amp;rsquo;t let this call run because you&amp;rsquo;re executing the malware itself.&lt;/p&gt;
&lt;h3 id="unpacking-the-malware-1"&gt;Unpacking the malware
&lt;/h3&gt;&lt;p&gt;The interesting part: this API call let us to dump the hidden payload stored inside the malware. So, breakpoint on it and let the malware run until it reaches the breakpoint. As before:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;NtWriteVirtualMemory(
IN HANDLE ProcessHandle,
IN PVOID BaseAddress,
IN PVOID Buffer,
IN ULONG NumberOfBytesToWrite,
OUT PULONG NumberOfBytesWritten OPTIONAL );
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basically we&amp;rsquo;re interested in two arguments, in particular: the &lt;em&gt;BaseAddress&lt;/em&gt; andthe &lt;em&gt;Buffer.&lt;/em&gt; These two parameters tell us where the buffer (the malware payload) will be written inside the newly created child&amp;rsquo;s memory. During its run, the malware makes a lot of calls to this function and I single stepped all of them: when breakpoint is reached, analyze the stack:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-12.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Focus on the third argument: &lt;strong&gt;0x064B6000&lt;/strong&gt; and follow it into the memory dump:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-13.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;It seems we found something interesting, uh? :-)&lt;/p&gt;
&lt;p&gt;We found that a PE file will be copied inside a memory address. Easy to dump it, right now: right click on to that address and follow it into memory map and after that dump that segment into a file.&lt;/p&gt;
&lt;p&gt;So we have dumped an entire segment into a bin file. We can open it with an hex editor, scroll down until we reach the start of PE file (MZ magic bytes) and clear all junk from MZ to the beginning of the dump. Save to a new exe file and we&amp;rsquo;re ready to open it with another great tool made by &lt;a class="link" href="https://twitter.com/hasherezade" target="_blank" rel="noopener"
&gt;hasherazade&lt;/a&gt;: &lt;strong&gt;PE Bear&lt;/strong&gt;. Luckily for us, IAT (Import Address Table) was not corrupted and we can see all the API the (real)malware calls when it runs.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-14.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;Basically we have unpacked the malware.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.kartone.ninja/images/2018/07/image-16.png"
loading="lazy"
&gt;&lt;/p&gt;
&lt;p&gt;I will try to update this post with the second part as soon as I&amp;rsquo;ll figure it out. :-)&lt;/p&gt;</description></item></channel></rss>