Referencing yourself with arguments.callee()

Obfuscation using arguments.callee() in java scripts is widely seen in  browser exploitation and malicious PDF attacks. This kind of obfuscation could be a bit tricky to handle for security analyst.

The arguments.callee() call is used normally to prevent security analyst from modifying the malicious function. The variable that holds the arguments.callee will be validated in order to detect whether code has be altered or not. If yes, then the code will generate  a false result or no result at all.

Based on the JavaScript reference, the variable that is assigned with arguments.callee() will store the function’s content where the call is residing. The example below is a simple JavaScript code that validates the length of the characters in the function’s content. If the function is altered and the length is increased, the false result will be called.

function malicious_fn(arg1, arg2) {
 var validate = arguments.callee.toString();
 if (validate.length <= 198) {
   eval(unescape(arg1));
 }
 else {
   eval(unescape(arg2));
 }
}

malicious_fn("%54%68%69%73%20%69%73%20%6d%61%6c%69%63%69%6f%75%73%21","%54%68%69%73%20%69%73%20%6e%6f%74%20%6d%61%6c%69%63%69%6f%75%73%21");

In order to bypass this kind of obfuscation trick, we can circumvent the trap by replacing the  variable ‘validate’ with the original malicious_fn function.

function malicious_fn(arg1, arg2) {
 var validate = unescape("%66%75%6e%63%74%69%6f%6e%20%6d%61%6c%69%63%69%6f%75%73%5f%66%6e%28%61%72%67%31%2c%20%61%72%67%32%29%20%7b%0d%0a%09%76%61%72%20%76%61%6c%69%64%61%74%65%20%3d%20%61%72%67%75%6d%65%6e%74%73%2e%63%61%6c%6c%65%65%2e%74%6f%53%74%72%69%6e%67%28%29%3b%0d%0a%0d%0a%09%69%66%20%28%76%61%6c%69%64%61%74%65%2e%6c%65%6e%67%74%68%20%3c%3d%20%31%39%38%29%20%7b%0d%0a%09%09%65%76%61%6c%28%75%6e%65%73%63%61%70%65%28%61%72%67%31%29%29%3b%0d%0a%09%7d%0d%0a%09%65%6c%73%65%20%7b%0d%0a%09%09%65%76%61%6c%28%75%6e%65%73%63%61%70%65%28%61%72%67%32%29%29%3b%0d%0a%09%7d%0d%0a%7d");

 if (validate.length <= 198) {
   eval(unescape(arg1));
 }
 else {
   eval(unescape(arg2));
 }
}

malicious_fn("%54%68%69%73%20%69%73%20%6d%61%6c%69%63%69%6f%75%73%21","%54%68%69%73%20%69%73%20%6e%6f%74%20%6d%61%6c%69%63%69%6f%75%73%21");

This example code is just a basic demonstration of how arguments.callee() is practically being used in real malicious code. Bear in mind that there are hundreds of ways arguments.callee() can be used to make your life miserable as an analyst. The is only  way for us to handle this annoyance is by understanding how the code works.

Yara Rule For CVE-2010-0805

The Internet Explorer Tabular Data Control ActiveX Memory Corruption (CVE-2010-0805) exploit was recently ported to Metasploit, so we decided to release the detection rule for Yara. Yes it can also be used with JSunpack!

rule MSIETabularActivex
{
        meta:
                ref = "CVE-2010-0805"
                impact = 7
                hide = true
        strings:
                $cve20100805_1 = "333C7BC4-460F-11D0-BC04-0080C7055A83" nocase fullword
                $cve20100805_2 = "DataURL" nocase fullword
                $cve20100805_3 = /value\=\"http:\/\/(.*?)\"/ nocase fullword
        condition:
               ($cve20100805_1 and $cve20100805_3) or (all of them)
}

Credit:

  1. ZSploit.com
  2. Metasploit
  3. @d3t0n4t0r

pKaji: The PHP Analyzer

pKaji is a free service provided by MyCERT that allows one to analyze  PHP codes.  It facilitates detection of network activities and other potentially malicious activities within the code by using the ‘hooking’ technique. Basically, it uses the APD (Advance PHP Debugger) extension to hook the original PHP built-in function.

Using pKaji

To use pKaji, a user can upload a valid PHP file to pKaji with a size smaller than 1 Mb at https://blog.honeynet.org.my/pKaji/. The front-end of pKaji will forward the request to the pKaji-core engine. The process will probably take a few minutes depending on the server workload.

Result of the analysis will be in shown in xml format displaying each of the parameter sent to the function called.

Output Example

PHP code XML Output
set_time_limit(0); <function_call>
<name>set_time_limit</name>
<parameter>seconds=0</parameter>
</function_call>
fsockopen(“irc.neoshell.org”,”6667”, &$err_num, &$err_msg, 30); <function_call>
<name>fsockopen</name>

<parameter>host=irc.neoshell.org, port=6667, , , 30</parameter>
</function_call>

echo “ID: ShiroHige<br>”; <function_call>
<name>echo</name>
<parameter>$str=”ID: ShiroHige<br>”</parameter>

</function_call>

@getenv(“SERVER_ADDR”); <function_call>
<name>getenv</name>

<parameter>$varname=SERVER_ADDR</parameter>
</function_call>

To upload a file, you need to have account. You can request the login credentials via email honeynet [at] cybersecurity.my . Just tell us a bit about yourself and be patient 🙂 We definitely look forward to working with security teams and researchers in the future.

Bashing The Wildcard

This is quick note about wildcard usage for the  Linux command line particularly on  how to select/include some files among the others.

Let say you have a directory  that contains the following files:

$ls mh
apache-log.tar.gz.00
apache-log.tar.gz.01
apache-log.tar.gz.02
apache-log.tar.gz.03
apache-log.tar.gz.04
apache-log.tar.gz.05
apache-log.tar.gz.06
apache-log.tar.gz.07
apache-log.tar.gz.08
apache-log.tar.gz.09
apache-log.tar.gz.10
apache-log.tar.gz.11
apache-log.tar.gz.12
apache-log.tar.gz.13

To copy the first 10 files,  you can do this

$cp apache*0[0-9] cperdana/

The command will copy file apache-log.tar.gz.00 to apache-log.tar.gz.09 into the cperdana. The key here is that the  * and the square bracket character.

Now comes the tricky part. How  do you copy the last 9 of the files (apache-log.tar.gz.05 – apache-log.tar.gz.13)

In regular expression, I would put the ‘OR’ character (|), which looks like this:
$cp apache*(0[5-9]|1[0-3]) cperdana/

But apparently, this will not produce the expected result, instead bash will throw an error.

So how to do that?
The magic character we are looking is the ‘curly bracket’ 🙂
$ls manchaster{United,City}
will result manchasterUnited and manchasterCity only.

As our problem, here how to go about it
$cp apache*{0[5-9],1[0-3]} cperdana/

/Info does give an info :)

Common PDF dictionary used inside malicious PDF are /Author, /Producer, /Title, and /Subject which use reference from this.info.author, this.info.producer, this.info.title, and this.info.subject respectively.

The PDF dictionary mentioned above are located inside the /Info referenced object. This can be identified from the reference variable above (e.g: this.info.title) used inside JavaScript code. For instance;

this /* means that in this very own PDF file */
.
info /* which refer to the object of /Info */
.
title /* which refer to the /Title object reference */

However, recently, I’ve stumbled upon a PDF dictionary that is not defined inside the  PDF Reference. By reading through its reference variable, this.info.autor, it is certain that the obfuscated malicious code reside in the object referenced at /autor.

Check the trailer dictionary (usually at the end of PDF content) to view the object number referenced to /Info. In this case, object 9 0 R

From object 9 0, we know /autor is reference to content inside object 5 0 R


Snippet from object 5 0 R

Observation of Common String Obfuscation Trick

String obfuscation has become an enemy of string/pattern matching since forever. With string obfuscation tricks, string/pattern matching with no proper handling will surely return no significant results. This kind of tricks has to be taken into consideration when developing a security tool with string/pattern matching as its one of the main engine.

In this post, we will going to look at few (yet famous) of the common obfuscation trick that are being used in JavaScript code.

String concatenation with “+” or ‘+’

This obfuscation trick is commonly being used in malicious JavaScript code. String concatenation in JavaScript functionalities allows actual string to be concatenated with the character “+” or ‘+’. For instance, document.write(“th”+”is”+” is “+”mal”+”iciou”+”s!”); are equivalent with document.write(“this is malicious!”); even though the form and length are not equal.

Comment

Comment obfuscation are also become a nuisance in deobfuscating the Javascript code. The previous example, document.write(“this is malicious!”); can also be represent into document/* comment 1 */.write/* comment 2 */(“this is malicious!”/* comment 3 */); which is also valid for code execution. This technique is also one of the preferred obfuscation to be included by attacker inside the malicious code.

Long spaces

Another annoying technique used in the malicious JavaScript code is the long spaces/tabs.  In long spaces/tabs, normal code like document.write(“this is malicious!”); usually will represent something like document.write( “this is malicious!”); depending on the attackers’ creativity.

Analyst might need to take a proper string handling before string/pattern matching detection took place since the mentioned string obfuscation tricks above will surely evade the success of string/pattern matching –based tool. It is undoubtedly that analyst will have to give a huge effort in order for analysis tool to be useful for future usage.

Keep in mind that all of the above tricks are part of the JavaScript’s valid functionalities. Most of the scripting language also provide this kind of features and functionalities, and most of the programmers are benefited in good ways with these functionalities. Its idea is not for obfuscation but rather for flexibility in programming style. But good usually packaged with bad, and manipulation of this good functionalities makes it become a obfuscation trick for destructive purposes.

DIONAEA:submission module

Mark Schloesser spoke about Dionea during his presentation at the  FIRST-TC KL 2009, last December and that got us really excited. A few MyCERT folks  had a chance to do a ‘class’ with him as well and got some exposure with the its internal.

We are replacing some of the nepenthes instances with  Dionaea . However, the lack of centralized logging and submission features on Dionaea, required us to code our own submission module. At first, it was a little bit confusing (due to my lack of understanding on Dionaea inner working code) on the process to build the module. After a few IRC sessions (Dionaea’s IRC is @freenode on #nepenthes) with Markus ( Dionaea Developer) , we managed to get the module working (we dump binaries and connection log too). Below is some output from submission log:

2010-01-29 :12:05:26	sensor1	lala@gmail.com	192.168.93.1	51419	192.168.93.130	135	http://192.168.93.1/~mahmud/hafix.exe	attempt
2010-01-29 :12:06:03	sensor1	lala@gmail.com	192.168.93.1	51421	192.168.93.130	135	http://192.168.93.1/~mahmud/hafix.exe	attempt
2010-01-29 :12:06:03	sensor1	lala@gmail.com	192.168.93.1	51421	192.168.93.130	135	http://192.168.93.1/~mahmud/hafix.exe	success	e28b655de7fd0ec1ac3d2d6fc9c65094
2010-01-31 :02:23:16	sensor1	lala@gmail.com	192.168.93.1	60496	192.168.93.130	135	http://192.168.93.1/~mahmud/hafix.exe	attempt

Below is the module for the submission (bare in mind, that this my 1st time coding in Python). Please refer to few modules such as surfids.py,logsql.py, test.py to have more examples on using the modules.

from dionaea import ihandler, incident, g_dionaea
from dionaea import connection
import logging
import json
import time
global p

logger = logging.getLogger('submission')
logger.setLevel(logging.DEBUG)

class mycertsubmitdownloadihandler(ihandler):
        def __init__(self, path):
                logger.debug("%s ready!" % (self.__class__.__name__))
                ihandler.__init__(self, path)
        def handle_incident_dionaea_download_complete_hash(self,icd):
                logger.debug("submitting file to submission server")
                try:
                        tos = g_dionaea.config()['submission']
                except:
                        return

                for to in tos:
                        if 'urls' not in g_dionaea.config()['submission'][to]:
                                logger.warn("your configuration lacks urls to submit to %s" % to)
                                continue
                        for url in g_dionaea.config()['submission'][to]['urls']:
                                i = incident("dionaea.upload.request")
                        #       i=icd
                                i.url = url
                                i.flags = 'success'
                                i.file = icd.file
                                i.repo_ip = icd.url
                                i.attacker_ip = icd.con.remote.host
                                i.sensor_ip = icd.con.local.host
                                i.timestamp = str(time.strftime("%Y%m%d:%H:%M:%S", time.localtime()))
                                i.md5 = icd.md5hash
                                i.attacker_port = str(icd.con.remote.port)
                                i.sensor_port = str(icd.con.local.port)

                                # copy all values for this url for submission's section
                                for key in g_dionaea.config()['submissiont'][to]:
                                        if key == 'urls':
                                                continue

                                        i.set(key, g_dionaea.config()['submission'][to][key])
                                i.report()

        def handle_incident_dionaea_download_offer(self, icd):
                logger.debug("submitting attempt download info  to submission server")
                try:
                        tos = g_dionaea.config()['submission']
                except:
                        return

                for to in tos:
                        if 'urls' not in g_dionaea.config()['submission'][to]:
                                logger.warn("your configuration lacks urls to submit to %s" % to)
                                continue
                        for url in g_dionaea.config()['submission'][to]['urls']:
                                i = incident("dionaea.upload.request")
                                i.url = url
                                #i.file = icd.file
                                i.flags='attempt'
                                i.repo_ip = icd.url
                                i.attacker_ip = icd.con.remote.host
                                i.sensor_ip = icd.con.local.host
                                i.timestamp = str(time.strftime("%Y%m%d:%H:%M:%S", time.localtime()))
                                #i.md5 = icd.md5hash
                                i.attacker_port = str(icd.con.remote.port)
                                i.sensor_port = str(icd.con.local.port)

                                # copy all values for this url for submission's section
                                for key in g_dionaea.config()['submission'][to]:
                                        if key == 'urls':
                                                continue
                                        i.set(key, g_dionaea.config()['submission'][to][key])
                                i.report()

The Dionaea’s config file need to be changed to reflect the module. Here is the sample for the Dionaea’s config (only portion of submission’s part):

submission =
{
        mysubmit =
        {
                urls = ["http://your_url_here/upload.php"]
                sensorname="sensor1"
                email = "lala@gmail.com"
                file_fieldname = "upfile"
                user = "user1"
                MAX_FILE_SIZE = "1500000"
                pass = "yourpassword"
                submit        = "Submit for analysis"
        }
}

As for upload.php, you can use similar code here (warning: this is just a sample code, modify accordingly to fit your security requirements):

Email:
Filename:
[php start] #blog failed to render php start tag $flag_download=$_POST['flags']; //for flag about success download or attemp [will check against data submit by module] $timestamp= $_POST['timestamp']; $sensor = $_POST['sensorname']; $email = $_POST['email']; $attacker_ip = $_POST['attacker_ip']; $attacker_port = $_POST['attacker_port']; $repo_ip = $_POST['repo_ip'];$sensor_ip = $_POST['sensor_ip']; $sensor_port= $_POST['sensor_port']; $md5hash=$_POST['md5']; //test logging into text file $stringData =$timestamp ."\t" . $sensor ."\t" .$email ."\t" . $attacker_ip ."\t" . $attacker_port ."\t" . $sensor_ip ."\t" . $sensor_port ."\t" . $repo_ip ."\t" . $flag_download ."\t" .$md5hash ."\n"; $myFile = "testFile.txt"; $fh = fopen($myFile, 'a') or die("can't open file"); fwrite($fh, $stringData); if(preg_match("/php/i",$_FILES["upfile"]["name"])) { echo "wthexx?? "; exit(); } else { echo "Upload: " . $_FILES["upfile"]["name"] . ""; echo "Type: " . $_FILES["upfile"]["type"] . ""; echo "Size: " . ($_FILES["upfile"]["size"] / 1024) . " Kb"; echo "Temp file: " . $_FILES["upfile"]["tmp_name"] . ""; if (file_exists("binaries/" . md5_file($_FILES["upfile"]["tmp_name"]))) { echo md5_file($_FILES["upfile"]["tmp_name"]) . " already exists. "; } else { move_uploaded_file($_FILES["upfile"]["tmp_name"],"binaries/". md5_file($_FILES["upfile"]["tmp_name"])); echo "Stored in: " . "binaries/" .md5_file($_FILES["upfile"]["tmp_name"]); } } [end php] #again, blog failed to render php end tag

Recently Markus mentioned about xmpp support on Dionaea. This is very exciting news as well. Now you’ve got a very flexible distributed environment for Dionaea.

For now, we’re happy with this implementation and will wait for xmpp support on Dionaea as well. 🙂

–  mahmud

Dionaea: Auto Start Script on Ubuntu

Getting Dionaea to run should be very straightforward for most people.  One of the thing we need for our project is  As for us, to get our Dionaea appliance running properly, one the feature we need is to get Dionaea service running when the OS is booting. Below is the script for it (shameless ripped off from Nepenthes’s script):

#! /bin/sh
### BEGIN INIT INFO
# Required-Start:    $network
# Required-Stop:     $network
# Should-Start:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/opt/dionaea/bin/dionaea
NAME=dionaea
GROUP=dionaea
CONFIG_FILE="/opt/dionaea/etc/dionaea/dionaea.conf"
#dionaea -u nobody -g nogroup -r /opt/dionaea/ -w /opt/dionaea -p /opt/dionaea/var/dionaea.pid
DAEMON_OPTS="-u $NAME -g $GROUP -l all,-debug -L '*'  -w /opt/dionaea -c $CONFIG_FILE"

test -x $DAEMON || exit 0

set -e

case "$1" in
  start)
	echo -n "Starting $NAME: "
	start-stop-daemon --start --quiet --oknodo --pidfile /opt/dionaea/var/$NAME.pid \
	--background --make-pidfile --exec $DAEMON -- $DAEMON_OPTS
	echo "$NAME."
	;;
  stop)
	echo -n "Stopping $NAME: "
	start-stop-daemon --stop --quiet --oknodo --pidfile /opt/dionaea/var/$NAME.pid \
	--signal 15 --exec $DAEMON
	echo "$NAME."
	;;
  restart|force-reload)
	echo -n "Restarting $NAME: "
	start-stop-daemon --stop --quiet --oknodo --pidfile /opt/dionaea/var/$NAME.pid \
	--signal 15 --exec $DAEMON
	sleep 1
	start-stop-daemon --start --quiet --oknodo --pidfile /opt/dionaea/var/$NAME.pid \
	--background --make-pidfile --exec $DAEMON -- $DAEMON_OPTS
	echo "$NAME."
	;;
  *)
	N=/etc/init.d/$NAME
	echo "Usage: $N {start|stop|restart|force-reload}" >&2
	exit 1
	;;
esac

exit 0

Copy the script, rename it to dioanea and move it to /etc/init.d/

On Ubuntu, we need to activate this to reflect our desire init level for Dionaea script. Lets use defaults init :

shell$sudo update-rc.d dionaea defaults

To execute or start the dionaea service, just simply:

shell$sudo /etc/init.d/dionaea start

Crontab Problem

There was a problem in one of my bash scripts. The script (master-universe) is the starter of another script. It should be run daily at midnight to check  if a child process, which is the manager of the another script, is still running. If the child process is somehow dead, it will (re) execute the child.

theInduk.sh
	(call)  ---  master-universe.sh
		   (call)  ---   child_proses.sh

I tested the script with bash and /bin/sh, it seems to be  working just fine.

 kill_master() {
for pid in `ps aux| grep -v grep |grep 'master-universe' |awk '{print $2}'`; do
echo "Killing pid: " $pid
kill -9 $pid
done
}

The function above is the source of the problem. When it execute using crontab, it refused go inside the for loop as if  the process master-universe does not exist (checked via ps aux from cli).

My first thought was /bin/sh can’t interpret the for syntax for whatever reasons. But thats not true because when run it from the console

sh ./theInduk.sh

everything seemed allright.

After spending more than 1 hour debugging and nearly thrashing my mouse to the 19”  lcd, I realized it! I added a line to the code, and it revealed everything.

kill_master() {
ps aux > /tmp/napeTakSama.txt
for pid in `ps aux| grep -v grep |grep ‘master-universe’ |awk ‘{print $2}’`; do
echo “Killing pid: ” $pid
kill -9 $pid
done
}

Result of /tmp/napeTakSama.txt

root    809  0.0  0.0  5688   996  v3  Is+   2Jul09   0:00.00 /usr/libexec/gett
root    810  0.0  0.0  5688   996  v4  Is+   2Jul09   0:00.00 /usr/libexec/gett
root    811  0.0  0.0  5688   996  v5  Is+   2Jul09   0:00.00 /usr/libexec/gett
root    812  0.0  0.0  5688   996  v6  Is+   2Jul09   0:00.00 /usr/libexec/gett
root    813  0.0  0.0  5688   996  v7  Is+   2Jul09   0:00.00 /usr/libexec/gett
root  60580  0.0  0.0 20440  1624  p0  I     6Jan10   0:00.00 su
root  60581  0.0  0.1 10104  2712  p0  I+    6Jan10   0:00.02 _su (csh)
xmen 83289  0.0  0.1  9016  2248  p0  Is   21Jul09   0:00.04 /usr/local/bin/ba
root    941  0.0  0.1 10104  3104  p1  Is    2Jul09   0:00.10 /bin/csh
root  61684  0.0  0.1  9456  2980  p1  S+    6Jan10   0:11.10 tcpdump -avvv -i
root    971  0.0  0.1 10104  3084  p2  Is+   2Jul09   0:00.15 /bin/csh
xmen  3960  0.0  0.1  9016  2176  p3  Is    3Jul09   0:00.01 -bash (bash)
xmen  3966  0.0  0.0  8144  1716  p3  S+    3Jul09   0:23.29 screen -l
xmen  3970  0.0  0.1  9016  2176  p4  Is+   3Jul09   0:00.06 /usr/local/bin/ba
xmen  4029  0.0  0.1  9016  2252  p5  Is    3Jul09   0:00.12 /usr/local/bin/ba

Can you see the problem?

Yup.. the result of ps aux above is somehow truncated to 81 characters for each line and therefore my grep cannot find the master-universe string.

The Solution?
Instead of ps aux I just used ‘ps ax’ and filtered the first column.

for pid in `ps ax| grep -v grep |grep 'master-universe' |awk '{print $1}'`; do

The above code worked as I expected.

This happen on FreeBSD 7.2. (I hate bsd!) I tried the original code on Linux (Ubuntu Karmic) and  guess what? The result is as expected from a well behaved innocent OS.

(Note to myself: Remember, always love Linux).

OllyScript – Automating detection and unpacking the Conficker Worm Variant B/C

In order to bring the problem of extracting unpacking code into the realm of decidability,  MyCERT had been working on  automating the unpacking script in an assembly-like language. The script, called OllyScript,  can be used to unpack malicious worm Win32/Conficker B and Win32/Conficker C. OllyScript is the scripting language plugin for OllyDbg.  It simulates user’s debugging session within OllyDbg.

OllyScript is important when dealing with PE packer; it can take hours to unpack a single protector where users no need to do it too often. The unpacked code extraction algorithm as URL [https://blog.honeynet.org.my/mirror/Unpack_ConfickerBC.txt] operates by identifying the version of Conficker worm of an input binary executable file. An automating uncompressing code is executed to unpack the obfuscation code.

The instruction on how to run the “Unpack_ConfickerBC.txt” using OllyDBG please refer to previous post [https://blog.honeynet.org.my/?p=81].