Fixing OSMO-FL2K Dongle that only works in USB 2.0

TLDR: If your FL2K dongle only works on USB 2.0 ports, it may have been wired incorrectly. Rewiring it should make it work.

Two weeks ago I learned about osmo-fl2k from Hackaday and immediately ordered one from Aliexpress. Two days ago, I received my order and tested it: it works with USB 2.0 ports on all of my computers (Windows and Linux, Desktop and Laptop), but when I plugged it in on a USB 3.0 port, it is not detected at all.

I verified that the device ID is as expected by osmo-fl2k and that it works (with fl2k-test) on USB  2.0 port  although it is very slow (14 MS/s).

The device is never detected on USB 3.0 ports, with or without hubs. No message at all when typing “dmesg”, and Windows also doesn’t show anything on device manager (not even a blink on device manager when the device is plugged in). I verified that all of my USB 3.0 port works by plugging other USB 2.0 and USB 3.0 devices.

Next step is to open this thing to verify that I really get the correct chip. Fortunately, the chip is correct, although the PCB is a bit different from the one shown in the osmo-fl2k website. The cable soldering seems to be ok, the connection looks good, and they even hot-glue it to make sure it stays that way.

I began to notice that the cabling is a bit different from the one shown in osmo-fl2k website. On the website all 10 cables is on the front side of the PCB, and on mine there are only 8 of them on one side and two on the other side.

I began to suspect something is wrong with the SSTX+/SSTX-/SSRX+/SSRX- cabling.  But there is no specification/datasheet for the Chip, so how can I know the correct cabling?

First I tried using my multimeter’s continuity tester to check the color of the cables and the connection. It matches the standard coloring as listed in the USB 3.0 page on Wikipedia. For example, testing D+ pin on the USB port shows that it connects to the green cable and D- connects to the white cable.

I made an assumption: the quality of dongle used on the FL2K website looks good (mine doesn’t even have the SPI flash chip), so I assume they also use standard colors for the cables. Tracing from the pins to the cable shows that I need to rearrange the cables to match. For example, the first two pins on the top right of the chip should go to purple and orange cables (SuperSpeed receiver differential pair).

Image from osm-fl2k website

After rewiring it, it works fine, the dongle is detected on USB 3.0 ports and I can transmit up to 108MS/s. I have an old motherboard (>5 years), and as you can see from the osmo-fl2k website that the transmission speed depends on the USB 3.0 controller that you have. I have successfully transmitted FM radio signal but I haven’t experimented with other types of signal yet.

After unsoldering and resoldered the cables

So the explanation of why it works on USB 2.0 ports is because it only uses VCC, GND, D+, and D- which was wired correctly. While on USB 3.0 ports, it tried to use the SSTX/SSRX pair and it doesn’t work.

I hope this helps others that have the same problem. Just a word of caution: the colors of your cables might be different from the one that I have, the PCB layout that you receive may also be different, so be careful and double check everything.

Pentesting obfuscated Android App

I just finished pentesting a mobile app for a financial institution. I wrote this mainly as a note for future manual deobfuscation work. I have read a lot of articles and tested tools to deobfuscate Android apps but they are mostly for analyzing malware. Sometimes I need to deobfuscate and test app for the pentesting purpose.

Most of the time it doesn’t matter whether we are analyzing malware or analyzing some apps, but there are differences. For example, when testing a bank or financial app (with a team):

  • We can be sure that the app is not malicious, so we can safely use real device
  • The obfuscation is usually only up to DEX level, and will not patch the native code (Dalvik VM), because they want to ensure portability
  • We need to be able to run and test the app, not just extract strings to guess the capability of the app (on some malware analysis, you just need to extract strings)
  • Sometimes we need to modify and repack the app to bypass root checking, SSL pinning, etc and redistribute the APK to team members (you don’t usually repack a malware APK for testing)

You may ask: if this is for pentesting, why don’t you just ask for the debug version of the app? In many cases: yes we can have it, and it makes our job really easy. In some cases, due to a contract between the bank and the app vendor (or some other legal or technical reasons), they can only give a Play Store or iTunes URL.

I can’t tell you about the app that I tested, but I can describe the protection used.

Try automated tools

Before doing anything manually, there are several deobfuscator tools and website that can help many obfuscation cases. One of them is APK Deguard. It only works with APK file up to 16 Mb, so if you have a lot of asset files, just delete the assets to get within the limit. This tool can recognize libraries, so you will sometimes get perfectly reconstructed method and class names. Unfortunately, there are also bugs: some variables are methods just disappear from a class. And sometimes it generates classes with 4 bytes in size (just the word: null).

I tried several other tools that looked promising, such as simplify (really promising, but when I tested it, it’s really slow). I also tried: Dex-Oracle (it didn’t work). JADX also has some simple renamer for obfuscated names, but it was not enough for this case.

Every time I found a tool that doesn’t work, I usually spend some time to see if I can make it work. In the end, sometimes manual way is the best.

Use XPosed Framework

In some cases, using XPosed framework is nice, I can log any methods, or replace existing methods. One thing that I don’t quite like is that we need to do reboot (or soft reboot) every time we update the modules.

There are also modules such as JustTrustMe that works with many apps to bypass SSL Pinning check. But it doesn’t work with all apps. For example, last time I checked didn’t work for Instagram (but of course, someone could have patched it now to make it work again).  RootCloak also works to hide root from most apps, but this module hasn’t been updated for quite some time.

Sadly for the app that I tested, both tools didn’t work, the app was still able to detect that the device is rooted, and SSL pinning is still not bypassed.

Use Frida

Frida is also an interesting tool that works most of the time. Some interesting scripts were already written or Frida, for example: appmon.

Both Frida and XPosed have a weakness in tracing execution inside a method. For example we cant print a certain value in the middle of a method.

Unpack and Repack

This is the very basic thing: we will check whether the app checks for its own signature. Initially, I use a locked bootloader, unrooted,  real device (not an emulator). We can unpack the app using apktool:

apktool d app.apk
cd app
apktool b

Re-sign the dist/app.apk and install it on the device. In my case: the app won’t run: just a toast displaying: “App is not official”.

Find Raw Strings

We can use:

grep -r const-string smali/

To extract all strings in the code. In my case: I was not able to find many strings. On the string that I did find, it was used for loading class. It means that: we need to be careful when renaming a class: it could be referenced from somewhere else as a string.

Add Logging Code

With some effort, we can debug a smali project, but I prefer debug logging for doing two things: deobfuscating string and for tracing execution.

To add debugging, I created a Java file which I then compile to smali. The method can print any java Object. First, add the smali file for debugging to the smali directory.

To insert logging code manually, we just need to add:

invoke-static {v1}, LLogger;->printObject(Ljava/lang/Object;)V

replace v1 with the register that we want to print.

Most of the times, the deobfuscator method has the same parameter and return everywhere, in this case, the signature is:

.method private X(III)Ljava/lang/String;

We can write a script that:

  1. Finds deobfuscation method
  2. Inject a call to log the String

Printing the result string in the deobfuscate method is easy, but we have a problem: where (which line, which file) does the string comes from?

We can add logging code with more information like this:

const-string v1, "Line 1 file http.java"    
invoke-static {v1}, LMyLogger;->logString(Ljava/lang/String;)V

But it would require unused register for storing string (complicated, need to track which registers are currently unused), or we could increase local register count and use last register (doesn’t work if method already used all the registers).

I used another approach: we can use a Stack Trace to trace where this method is called. To identify the line, we just add new “.line” directive in the smali file before calling the deobfuscate method. To make the obfuscated class name easier to recognize, add a “.source” at the top of the smali. Initially we don’t know yet what the class do, so just give a unique identifier using uuid.

Tracing Startup

In Java, we can create static initializer, and it will be executed (once) when the class is used the first time. We should add logging code at beginning of <clinit>.

class Test {    
static { System.out.println("test"); }
}

I used UUID here (I randomly generate UUID and just put it as constant string in every class) that will helps me work with obfuscated name.

class Test {    
static {
System.out.println("c5922d09-6520-4b25-a0eb-4f556594a692"); }
}

If that message appears in logcat, then we know that the class is called/used. I could do something like this to edit the name:

vi $(grep -r UUID smali|cut -f 1 -d ':' )

Or we can also setup a directory full of UUIDS with symbolic link to the original file.

Writing new smali code

We can easily write simple smali code by hand, but for more complicated code we should just write in Java, and convert it back to smali. It is also a good idea to make sure it works on the device.

javac *.java
dx --dex --output=classes.dex *.class
zip Test.zip classes.dex
apktool d Test.zip

Now we get a smali that we can inject (copy to the smali folder)

This approach can also be used to test part of code from the app itself. We can extract smali code, add main, and run it.

adb push Test.zip /sdcard/
adb shell ANDROID_DATA=/sdcard dalvikvm -cp /sdcard/Test.zip NameOfMainClass

Think in Java level

There are several classes in the app that  extracts a dex file from a byte array to a temporary name, and then removes the file. The array is encrypted and the filename is random. First thing that we want to know is: is this file important? Will we need to patch it?

To keep the file, we can just patch the string deobfuscator: if it returns “delete”, we just return “canRead”. The signature of the method is compatible which is “()Z” (a function that doesn’t receive parameter and returns boolean).

It turns out that replacing the file (for patching) is a bit more difficult. Its a bit complicated looking at the smali code, but in general this is what happens:

  1. It generates several random unicode character using SecureRandom (note that because this is a “secure” random, altering the seed of SecureRandom won’t give you predictable file names)
  2. It decrypts the built in array into a zip file in memory
  3. It reads the zip file from a certain fixed offset
  4. It deflates the zip file manually
  5. It writes the decompressed result to a random dex file name generated at step 1
  6. It loads the dex file
  7. It deletes the temporary dex file

I tried patching the byte array, but then I also need to adjust a lot of numbers inside (sizes and offsets). After thinking in Java level, the answer is just to create a new Java code that can do what we want. So this is what I did instead:

I created a class named: FakeOutputStream, then patched the code so instead of finding java.io.FileOutputStream, it will load FakeOutputStream.

The FakeOutputStream will write the original code to /sdcard/orig-x-y, with x and y is the offset and size AND instead it will load the content of /sdcard/fake-x-y and write it to the temporary file.

Using this: when I first run the app, it will generate /sdcard/orig-x-y, and I can reverse engineer the generated DEX. I can also modify the dex file, and push it as /sdcard/fake-x-y, and that file will be loaded instead.

Time to Patch

After we can decrypt all file contents, we can start patching things, such as removing root check, package signature check, debugger check, SSL pinning check, etc.

Having the dex file outside of the main APK has an advantage: we can easily test adding or replacing method just by replacing the dex file outside the app.

 

Flare-On 4: Challenge 9 Quick Solution

This is an Arduino (AVR) challenge. You can read the full official solution from FireEye, here I just want to show how we can just find use “grep” to quickly find the decryption function to get the flag.

At first, I was going to try to understand what this binary does, but before going too deep, I had an idea: this binary is so small, what if I can just find the flag string without looking at the program’s logic. Looking at the strings present in the binary, it is obvious The flag is not in cleartext, so it must be encrypted somehow.

Most encryption algorithm will involve the use of XOR (eor in AVR). Looking at the disassembly, all EORs are just to clear a register (e.g: eor r1, r1). There is only one eor in 0xaee that is not clearing a register (eor r25, r24), which is the last one in this grep output.

$ avr-objdump -m avr -D remorse.ino.hex |grep eor
      c4:	11 24       	eor	r1, r1
     1ec:	99 27       	eor	r25, r25
     2e6:	99 27       	eor	r25, r25
     340:	11 27       	eor	r17, r17
     59e:	88 27       	eor	r24, r24
     742:	11 24       	eor	r1, r1
     78e:	11 24       	eor	r1, r1
     7f2:	11 24       	eor	r1, r1
     904:	11 24       	eor	r1, r1
     a16:	11 24       	eor	r1, r1
     aee:	98 27       	eor	r25, r24

Looking at the code around it: it is a single loop, with eor and subi. This must be the decrypt loop.

  ae6:       ldi     r26, 0x6C       ; 108
  ae8:       ldi     r27, 0x05       ; 5
  aea:       ldi     r18, 0x00       ; 0

decrypt:
  aec:       ld      r25, Z+
  aee:       eor     r25, r24
  af0:       add     r25, r18
  af2:       st      X+, r25
  af4:       subi    r18, 0xFF       ; 255
  af6:       cpi     r18, 0x17       ; 23
  af8:       brne    .-14            ; 0xaec 

We just need to find the encrypted data pointed by Z (which is a pair of R31:R30), and r24 (the xor key). Looking a bit up, we found the code that fills in the encrypted data. It sets Z with the value of Y (pair of R29:R28), clears the memory, and fill it with some bytes.

  a80:   movw    r30, r28        ; Z = Y
  a82:   adiw    r30, 0x01       ; Z++
  a84:   movw    r26, r30        ; X = Z
  a86:   ldi     r25, 0xFF       ; 
  a88:   add     r25, r30        ; 

clear:
  a8a:   st      X+, r1
  a8c:   cpse    r25, r26
  a8e:   rjmp    .-6             ; 0xa8a 

  a90:   ldi     r25, 0xB5 
  a92:   std     Y+1, r25  
  a94:   std     Y+2, r25  
  a96:   ldi     r25, 0x86 
  a98:   std     Y+3, r25  
  a9a:   ldi     r25, 0xB4 
  a9c:   std     Y+4, r25  
  a9e:   ldi     r25, 0xF4 
  aa0:   std     Y+5, r25  
  aa2:   ldi     r25, 0xB3 
  aa4:   std     Y+6, r25  
  aa6:   ldi     r25, 0xF1 
  aa8:   std     Y+7, r25  
  aaa:   ldi     r18, 0xB0 
  aac:   std     Y+8, r18  
  aae:   std     Y+9, r18  
  ab0:   std     Y+10, r25 
  ab2:   ldi     r25, 0xED 
  ab4:   std     Y+11, r25 
  ab6:   ldi     r25, 0x80 
  ab8:   std     Y+12, r25 
  aba:   ldi     r25, 0xBB 
  abc:   std     Y+13, r25 
  abe:   ldi     r25, 0x8F 
  ac0:   std     Y+14, r25 
  ac2:   ldi     r25, 0xBF 
  ac4:   std     Y+15, r25 
  ac6:   ldi     r25, 0x8D 
  ac8:   std     Y+16, r25 
  aca:   ldi     r25, 0xC6 
  acc:   std     Y+17, r25 
  ace:   ldi     r25, 0x85 
  ad0:   std     Y+18, r25 
  ad2:   ldi     r25, 0x87 
  ad4:   std     Y+19, r25 
  ad6:   ldi     r25, 0xC0 
  ad8:   std     Y+20, r25 
  ada:   ldi     r25, 0x94 
  adc:   std     Y+21, r25 
  ade:   ldi     r25, 0x81 
  ae0:   std     Y+22, r25 
  ae2:   ldi     r25, 0x8C 
  ae4:   std     Y+23, r25 

Going a bit up again, we found a ret (return), which means its the end of another function/subroutine. It seems that r24 is filled somewhere else by the caller of this decrypt function.

It doesn’t matter, r24 is just an 8 bit register (256 possible values). Translating this to python, with a brute force loop:

a = "b5b586b4f4b3f1b0b0f1ed80bb8fbf8dc68587c094818c".decode("hex")

for key in range(0, 256):
        s = ''
        for i,c in enumerate(a):
                m = ((ord(c)^key) + i)&0xff
                s = s + chr(m)
        print key, hex(key), s

And since all flags always have a flare-on.com suffix, we can just add a grep:

$ python brute.py|strings|grep flare
219 0xdb [email protected]

So the flag is [email protected] and the key is 219 decimal (0xdb).

Mastercard Internet Gateway Service: Hashing Design Flaw

Last year I found a design error in the MD5 version of the hashing method used by Mastercard Internet Gateway Service. The flaw allows modification of transaction amount.  They have awarded me with a bounty for reporting it. This year, they have switched to HMAC-SHA256, but this one also has a flaw (and no response from MasterCard).

If you just want to know what the bug is, just skip to the Flaw part.

What is MIGS?

When you pay on a website, the website owner usually just connects their system to an intermediate payment gateway (you will be forwarded to another website). This payment gateway then connects to several payments system available in a country. For credit card payment, many gateways will connect to another gateway (one of them is MIGS) which works with many banks to provide 3DSecure service.

How does it work?

The payment flow is usually like this if you use MIGS:

  1. You select items from an online store (merchant)
  2. You enter your credit card number on the website
  3. The card number, amount, etc is then signed and returned to the browser which will auto POST to intermediate payment gateway
  4. The intermediate payment gateway will convert the format to the one requested by MIGS, sign it (with MIGS key), and return it to the browser. Again this will auto POST, this time to MIGS server.
  5. If 3D secure not requested, then go to step 6. If 3D secure is requested, MIGS will redirect the request to the bank that issues the card, the bank will ask for an OTP, and then it will generate HTML that will auto POST data to MIGS
  6. MIGS will return a signed data to the browser, and will auto POST the data back to the intermediate Gateway
  7. Intermediate Gateway will check if the data is valid or not based on the signature. If it is not valid, then error page will be generated
  8. Based on MIGS response, payment gateway will forward the status to the merchant

Notice that instead of communicating directly between servers, communications are done via user’s browser, but everything is signed. In theory, if the signing process and verification process is correct then everything will be fine. Unfortunately, this is not always the case.

Flaw in the MIGS MD5 Hashing

This bug is extremely simple. The hashing method used is:

MD5(Secret + Data)

But it was not vulnerable to hash length extension attack (some checks were done to prevent this). The data is created like this: for every query parameter that starts with vpc_, sort it, then concatenate the values only, without delimiter. For example, if we have this data:

Name: Joe
Amount: 10000
Card: 1234567890123456

vpc_Name=Joe&Vpc_Amount=10000&vpc_Card=1234567890123456

Sort it:

vpc_Amount=10000
vpc_Card=1234567890123456
vpc_Name=Joe

Get the values, and concatenate it:

100001234567890123456Joe

Note that if I change the parameters:

vpc_Name=Joe&Vpc_Amount=1&vpc_Card=1234567890123456&vpc_B=0000

Sort it:

vpc_Amount=1
vpc_B=0000
vpc_Card=1234567890123456
vpc_Name=Joe

Get the values, and concatenate it:

100001234567890123456Joe

The MD5 value is still the same. So basically, when the data is being sent to MIGS, we can just insert additional parameter after the amount to eat the last digits, or to the front to eat the first digits, the amount will be slashed, and you can pay a 2000 USD MacBook with 2 USD.

Intermediate gateways and merchant can work around this bug by always checking that the amount returned by MIGS is indeed the same as the amount requested.

MasterCard rewarded me with 8500 USD for this bug.

Flaw in the  HMAC-SHA256 Hashing

The new HMAC-SHA256 has a flaw that can be exploited if we can inject invalid values to intermediate payment gateways. I have tested that at least one payment gateway (Fusion Payments) have this bug. I was rewarded 500 USD from Fusion Payments. It may affect other Payment gateways that connect to MIGS.

In the new version, they have added delimiters (&) between fields,  added field names and not just values, and used HMAC-SHA256.  For the same data above, the hashed data is:

Vpc_Amount=10000&vpc_Card=1234567890123456&vpc_Name=Joe

We can’t shift anything, everything should be fine. But what happens if a value contains & or = or other special characters?

Reading this documentation, it says that:

Note: The values in all name value pairs should NOT be URL encoded for the purpose of hashing.

The “NOT” is my emphasis. It means that if we have these fields:

Amount=100
Card=1234
CVV=555

It will be hashed as: HMAC(Amount=100&Card=1234&CVV=555)

And if we have this (amount contains the & and =)

Amount=100&Card=1234
CVV=555

It will be hashed as: HMAC(Amount=100&Card=1234&CVV=555)

The same as before. Still not really a problem at this point.

Of course, I thought that may be the documentation is wrong, may be it should be encoded. But I have checked the behavior of the MIGS server, and the behavior is as documented. May be they don’t want to deal with different encodings (such as + instead of %20).

There doesn’t seem to be any problem with that, any invalid values will be checked by MIGS and will cause an error (for example invalid amount above will be rejected).

But I noticed that in several payment gateways, instead of validating inputs on their server side, they just sign everything it and give it to MIGS. It’s much easier to do just JavaScript checking on the client side, sign the data on the server side, and let MIGS decide whether the card number is correct or not, or should the CVV be 3 or 4 digits, is the expiration date correct, etc. The logic is: MIGS will recheck the inputs, and will do it better.

On Fusion Payments, I found out that it is exactly what happened: they allow any characters of any length to be sent for the CVV (only checked in JavaScript), they will sign the request and send it to MIGS.

Exploit

To exploit this we need to construct a string which will be a valid request, and also a valid MIGS server response. We don’t need to contact MIGS server at all, we are forcing the client to sign a valid data for themselves.

A basic request looks like this:

vpc_AccessCode=9E33F6D7&vpc_Amount=25&vpc_Card=Visa&vpc_CardExp=1717&vpc_CardNum=4599777788889999&vpc_CardSecurityCode=999&vpc_OrderInfo=ORDERINFO&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256

and a basic response from the server will look like this:

vpc_Message=Approved&vpc_OrderInfo=ORDERINFO&vpc_ReceiptNo=722819658213&vpc_TransactionNo=2000834062&vpc_TxnResponseCode=0&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256

In the Fusion Payment’s case, the exploit is done by injecting  vpc_CardSecurityCode (CVV)

vpc_AccessCode=9E33F6D7&vpc_Amount=25&vpc_Card=Visa&vpc_CardExp=1717&vpc_CardNum=4599777788889999&vpc_CardSecurityCode=999%26vpc_Message%3DApproved%26vpc_OrderInfo%3DORDERINFO%26vpc_ReceiptNo%3D722819658213%26vpc_TransactionNo%3D2000834062%26vpc_TxnResponseCode%3D0%26vpc_Z%3Da&vpc_OrderInfo=ORDERINFO&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256

The client/payment gateway will generate the correct hash for this string

Now we can post this data back to the client itself (without ever going to MIGS server), but we change it slightly so that the client will read the correct variables (most client will only check forvpc_TxnResponseCode, and vpc_TransactionNo):

vpc_AccessCode=9E33F6D7%26vpc_Amount%3D25%26vpc_Card%3DVisa%26vpc_CardExp%3D1717%26vpc_CardNum%3D4599777788889999%26vpc_CardSecurityCode%3D999&vpc_Message=Approved&vpc_OrderInfo=ORDERINFO&vpc_ReceiptNo=722819658213&vpc_TransactionNo=2000834062&vpc_TxnResponseCode=0&vpc_Z=a%26vpc_OrderInfo%3DORDERINFO&vpc_SecureHash=THEHASH&vpc_SecureHashType=SHA256

Note that:

  1. This will be hashed the same as the previous data
  2. The client will ignore vpc_AccessCode and the value inside it
  3. The client will process the vpc_TxnResponseCode, etc and assume the transaction is valid

It can be said that this is a MIGS client bug, but the hashing method chosen by MasterCard allows this to happen, had the value been encoded, this bug will not be possible.

Response from MIGS

MasterCard did not respond to this bug in the HMAC-SHA256. When reporting I have CC-ed it to several persons that handled the previous bug. None of the emails bounced. Not even a “we are checking this” email from them. They also have my Facebook in case they need to contact me (this is from the interaction about the MD5 bug).

Some people are sneaky and will try to deny that they have received a bug report, so now when reporting a bug, I put it in a password protected post (that is why you can see several password-protected posts in this blog). So far at least 3 views from MasterCard IP address (3 views that enter the password).  They have to type in a password to read the report, so it is impossible for them to accidentally click it without reading it. I have nagged them every week for a reply.

My expectation was that they would try to warn everyone connecting to their system to check and filter for injections.

Flaws In Payment Gateways

As an extra note: even though payment gateways handle money, they are not as secure as people think. During my pentests  I found several flaws in the design of the payment protocol on several intermediate gateways. Unfortunately, I can’t go into detail on this one(when I say “pentests”, it means something under NDA).

I also found flaws in the implementation. For example Hash Length Extension Attack, XML signature verification error, etc. One of the simplest bugs that I found is in Fusion Payments. The first bug that I found was: they didn’t even check the signature from MIGS. That means we can just alter the data returned by MIGS and mark the transaction as successful. This just means changing a single character from F (false) to 0 (success).

So basically we can just enter any credit card number, got a failed response from MIGS, change it, and suddenly payment is successful. This is a 20 million USD company, and I got 400 USD for this bug.  This is not the first payment gateway that had this flaw, during my pentest I found this exact bug in another payment gateway. Despite the relatively low amount of bounty, Fusion Payments is currently the only payment gateway that I contacted that is very clear in their bug bounty program, and is very quick in responding my emails and fixing their bugs.

Conclusion

Payment gateways are not as secure as you think. With the relatively low bounty (and in several cases that I have reported: 0 USD), I am wondering how many people already exploited bugs in payment gateways.

Short write-up for Flare-On 2016

Fireeye has published the full write-up from the authors of the challenges, and at the time I wrote this, there is already one complete write-up (this) and I think many more will come. So instead of doing another full write-up, I will just write down things that I did differently and/or different tools that I used to solve the challenges.

Level 1

You can also use command line tr to use alternate base64 characters

echo x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q| tr ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/ ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/|base64 -d

Level 2

Same as most people: I just patched the executable to let it do the decryption

Level 3

Same as others: copy the memory after it is decrypted and do a bruteforce on it.

Level 4

I wrote a python script to find the longest call chain and call in that order.

I didn’t know that the decryption result supposed to be an executable that calls the beep() (“The decrypted data is a simple executable that makes a series of calls to the Beep API. “) . What I did find was just the string usetheforceluke!, and I searched the web for star wars theme song. And this one fits perfectly. I guess I was just very lucky.

Level 5

Instead of creating a disassembler, I reimplemented the emulator (if it had been a Linux binary, I would have tried WCC), and Identify the comparison points.

Initially I just manually try to find the requested values, but then I got bored and I just brute force every character and see if it would reach the next comparison point.

Level 6

I did it like everyone else.

Level 7

This is the first time I reversed a Go binary. I learned a lot by looking at the source code of gofrontend (especially the libgo part).

Level 8

I realized immediately that this is a DOS Code (from the name: Chiemera). I used Dosbox with heavy debugger (this forum post helps a lot).

Level 9

The first two levels can easily be solved using NoFuserEx and any .NET decompiler (I used ilspy).

I was not able to fix the third level with NoFuserEx, so I used reflection to load the third layer, then disassemble the instructions (using method.GetInstructions()). The pattern of the problem is the same as the first two layers, so I just need to find a reference to a field in StringUtils and find the reverse of the MD5.

Level 10

I used tshark to split the PCAP streams, and just used Chrome to reverse the Javascript part. It took a while before I found that we need to read this blog post to solve the Diffie Helman problem.

For the first part of the flash, I used JPEX open source flash decompiler. There a button to deobfuscate an SWF and that helped a lot.

Throughout the flash challenge, I didn’t use any native debugger , so I didn’t use both solution in “Searching Memory” in the official writeup page 26. Instead I used RABCDasm to disassemble and reassemble the ABC (actionscript byte code).

I created a new class to post data to a local URL, compiled the class, extract the byte code and copy it to the target.

amxmlc url.as
abcexport url.swf
rm -rf url-0
rabcdasm url-0.abc
cp url-0/*asm target-0

On top of the target-0.main.asasm add:

#include "url.script.asasm"

     getlex 		 QName(PackageNamespace(""), "url")
     pushbyte		 1
     callpropvoid	 QName(PackageNamespace(""), "testSendNumber"),1

Another example to send a byte array:

      dup #duplicate stack 
      getlex 		 QName(PackageNamespace(""), "url")
      swap #swap stack to correct the order
      callpropvoid	 QName(PackageNamespace(""), "testSendBA"),1 

On the last part, after we get the last .SWF, JPEXS is too slow to decompile the method. To solve this, I used RABCDasm again and use a simple python script to remove junk codes from the bytecode, rebuild the SWF then decompiled it with JPEXS.

I was a bit disappointed on this last challenge because I think it requires a bit guessing on the Imgur URL. I found the URL immediately, but I didn’t realize that it was important (I thought it was just an easter egg) until I saw the *size* of the image.

Conclusion

This year’s challenge was much harder than last year, I had much fun and I learned a lot from solving the challenges.

Teensy LC U2F key

Around beginning of last month, GitHub users can buy a special edition U2F security keys for 5 USD (5000 keys were available), and I got two of them. Universal 2nd Factor (U2F) is an open authentication standard that strengthens and simplifies two-factor authentication using specialized USB or NFC devices.

A U2F USB key is a second factor authentication device so it doesn’t replace our password. To login to a website, we need to enter our username and password, AND the U2F USB key. To check for user presence (to prevent malware from accessing the key without user consent), the device usually has a button that needs to be pressed when logging in.

Currently Google (Gmail, Google Drive, etc), Github, and Dropbox supports U2F devices, and we can also add support to our own site or apps using plugins or accessing the API directly (plugin for WordPress is available).

After receiving the keys, I got curious and started to read the U2F specifications. The protocol is quite simple, but so far I haven’t been able to find an implementation of a U2F key device using existing microcontrollers (Arduino or anything else). The U2F protocol uses ECC signing and I found that there is already a small ECC library for AVR and ARM (micro-ecc). It supports ECDSA with P-256 curve required by U2F.

IMG_5470

A U2F device is actually just a USB HID Device, so I will need something that I can easily program as an HID device. The easiest device to program that I have is Teensy LC. I tested compiling the micro-ecc library, and found out that it results in about 15 kilobytes of code, so Teensy LC should be OK (it has 64 kbyte flash, and 8KB of RAM). Teensy LC is also very small, it’s ideal if someday I want to put a case around it.

I can’t find an easy way to add new USB device using Teensyduino, so I decided to just patch the usb_desc.h, the only changes needed was to change the RAWHID_USAGE_PAGE to 0xf1d0 and RAWHID_USAGE to 0x01. I changed the PRODUCT_NAME to “Teensyduino U2FHID” just to make it easy to check that this works. The nice thing is: this doesn’t break anything (all code using RawHID would still run with this changes), and we can still see our code output using the virtual serial port provided by Teensyduino.

#elif defined(USB_RAWHID)
  #define VENDOR_ID		0x16C0
  #define PRODUCT_ID		0x0486
//  #define RAWHID_USAGE_PAGE	0xFFAB  // recommended: 0xFF00 to 0xFFFF
//  #define RAWHID_USAGE		0x0200  // recommended: 0x0100 to 0xFFFF
  #define RAWHID_USAGE_PAGE	0xf1d0  // recommended: 0xFF00 to 0xFFFF
  #define RAWHID_USAGE		0x01  // recommended: 0x0100 to 0xFFFF

  #define MANUFACTURER_NAME	{'T','e','e','n','s','y','d','u','i','n','o'}
  #define MANUFACTURER_NAME_LEN	11
  #define PRODUCT_NAME		{'T','e','e','n','s','y','d','u','i','n','o',' ','U','2','F','H','I','D'}

The U2F protocol is actually quite simple. When we want to use the hardware U2F key in a webapp (or desktop app), we need to add the USB key that we have to the app database. Practically, in the website, you would choose a menu that says “Add device” or “register new device”.

When you choose the register/add device, the app will send a REGISTER request to they hardware U2F USB key with a unique appid (for web app, this consist of domain name and port). The hardware U2F key will generate a private/public key pair specific for this app id, and the hardware U2F key will respond by sending a “key handle” and a “public key” to the app. If we have several usernames in an app/website, we can use a single hardware U2F key to be used for all accounts (the “key handle” will be different for each account).

Next time the user wants to login, the app/webapp will send authentication request to the hardware U2F key. In practice, when logging in, the website will request you to plug the hardware U2F key and press the button in the hardware key.

The app will send a random challenge and the appid (to identify which app it is), and the “key handle” (so the hardware U2F key will know which private key to use to sign the request). The hardware U2F key will reply with the same random challenge signed with the private key corresponding with the “key handle”, and it will also increase a counter (the counter is to prevent re-play attack and cloning attack).

There are two ways the hardware U2F key can keep track of which private key to use for a “key handle”: first one is to store a mapping of key handle to private key in a storage in the hardware U2F key, and when an app asks for a specific key handle, it can look up the private key in the storage. The second method is easier, and doesn’t require any storage, but slightly less secure: the “key handle” actually contains the private key itself (in encrypted form, otherwise anyone can send the request). Since the Teensy LC only contains 128 of EPROM, I used the second approach.

Google provides U2F reference code including something to test USB U2F keys. I started using this to test my implementation step by step using HidTest and U2Ftest. In retrospect this was not really necessary to get a working U2F key for websites. There are cases that just wouldn’t happen normally, and sometimes the test requires strange assumption (for example: as far as I know nothing in the specification says that key handle size must be at least 64 bytes in size).

Teensy LC doesn’t provide a user button (just a reset button), and I don’t want to add a button to it (it wouldn’t be portable anymore). So I just implemented everything without button press. This is insecure, but it’s ok for me for testing. For “key handle” I use a very simple xor encryption with fixed key which is not very secure. If you want a more secure approach, you can use a more complicated method.

Most of the time implementing your own device is not more secure than buying commercial solution, but sometimes it has some advantages over commercial solutions. For example: most devices that I know of doesn’t have a ‘reset’ mechanism. So if for instance you are caught having a device, and they have access to a website data, they can prove from your device that you have an account in that site (there is a protocol to check if a given key handle is generated by a hardware U2F device).

In our custom solution we can reset/reflash our own device (or just change the encryption key)) and have a plausible deniability that we are not related to that site (the suggestion in the U2F specification was to destroy a device if you no longer want to associate a website with your device if your device doesn’t have reset mechanism).

teensy

I have published my source in github in case someone wants to implement something similar for other devices (or to improve my implementation). I have included the micro-ecc source because I want to experiment by removing some unneeded functions to reduce the code size (for example: we always use uncompressed point representation for U2F, we only use a single specific Curve, we never need to verify a signature, etc). You should change the key “-YOHANES-NUGROHO-YOHANES-NUGROHO-” for your own device (must be 64 characters if you want security). There are still a lot of things that I want to explore regarding the U2F security, and having a device that I can hack will make things easier.

Update: some people are really worried about my XOR method: you can change the key and make it 64 bytes long. It’s basically a one-time-pad (xoring 64 bytes, with some unknown 64 bytes). If you want it to be more secure: change the XOR into anything else that you want (this is something that is not specified in the standard). Even a Yubico U2F device is compromised if you know the master key, in their blog post, they only mentioned that the master key is generated during manufacturing, and didn’t say if they also keep a record of the keys.

Update again: this is not secure, see http://www.makomk.com/2015/11/10/breaking-a-teensy-u2f-implementation/.

Regarding the buttonless approach: it’s really easy to add them. In my code, there is an ifdef for SIMULATE_BUTTON. It will just pretend that the button was not pressed on first request, and pressed on second request. Just change it so that it really reads a physical button.

Exploiting the Futex Bug and uncovering Towelroot

The Futex bug (CVE-2014-3153) is a serious bug that affects most Linux kernel version and was made popular by geohot in his towelroot exploit. You can read the original comex report at hackerone. Others have succesfully implemented this (this one for example), but no public exploit source code is available.

This post will describe in detail about what exactly is the futex bug, how to exploit the futex bug, and also explains how towelroot works and what the modstring in Towelroot v3 actually do. Following the footsteps of other security researchers, I will not give a full source code to the exploit. By giving enough details, I hope programmers can learn and appreciate the exploit created for this bug. By not releasing the source, I hope this should stop most script kiddies. There will be some small details that I will gloss over (about the priority list manipulation), so it will require some thinking and experimentation to implement the exploit.

One thing to note: I did some kernel programming, but never written a kernel exploit before, so this is my first time, I hope this is a good write up for a newbie exploit writer like me. Distributing the exploit source code will be useful only to handful of people, but writing about it will be useful to all programmers interested in this.

Towelroot is not opensource, and the binary is protected from reverse engineering by compiling it with llvm-obfuscator. When I started, I tried using 64 bit kernel on my desktop, and was not successful because I can’t find a syscall that can alter the stack in the correct location. So I decided to do a blackbox reverse engineering by looking at syscalls used by towelroot. Since (I think) I know how towelroot works, I will discuss about it, and I hope it will help people to understand/modify modstrings used in towelroot v3.

If you are an exploit hacker, just jump to “on to the kernel” part. The initial part is only for those unexperienced in writing exploits.

Before exploiting this bug we need to understand what the bug is. In short, the bug is that there is a data structure in the stack, that is part of a priority list that is left there and can be manipulated. This is very vague for most of programmers, so lets break it down. You need to understand what a stack is and how it works.

The Stack

A stack is a block of memory set aside for local variable, for parameter passing, and for storing return address of a procedure call. Usually when we talk about stack and exploits, we try to alter the return address and redirect it to another address and probably do ROP (Return Oriented Programming). This is not the case with this bug, so forget about that. Even though this bug is about futex, this is also not a race condition bug.

Stack memory is reused accross procedure calls (not cleared) . See this simple example:


You can compile then run it:

gcc test.c -o mytest

Note: just compile normally, don’t use any optimization level (-Ox):

$./mytest
local foo is 10
local foo is 12

As you can see, both procedures uses exactly the same stack layout. Both local uses the same stack location. When bar is called, it writes to the same stack location used by “foo” for its local variable. This simple concept will play a role in understanding the bug.

Next topic is about linked list. Usually a pointer based data structure uses heap for storing the elements (We don’t use stack because we want the elements to be “permanent” accross calls), but sometimes we can just use the stack, as long as we know that the element is going to be removed when the function exits, this will save time in allocation/deallocation. Here is an example of a made up problem where we put in an element located in the stack then removing it again before returning.

In that example, if we don’t remove the element and we return, the app will likely crash when the stack content is altered then the list js manipulated. That is the simplified version of the bug in the userland.

To exploit the bug, we need a good understanding of how futex work, especially the PI (Priority Inheritance Futex). There are very good papers that you can read about this topic. The first one is: Futexes Are Tricky, this will give a you an idea about what futex is and how it works. The other one is Requeue-PI: Making Glibc Condvars PI-Aware, this will give you a very thorough details about the PI futex implementation in the kernel. I suggest someone trying to implement the exploit to read at least the second paper.

For those of you who are not that curious to read the papers, I will try to simplify it: when there are tasks waiting for a pi futex, the kernel creates a priority list of those tasks (to be precise, it creates a waiter structure for that task) . A priority list is used because we want to maintain a property of a pi futex, i.e, task with a high priority will be waken first even though it waits after a low priority task.

The node of this priority list is stored in the kernel stack. Note that when a task waits for a futex, it will wait in kernel context, and will not return to user land. So the use of kernel stack here completely makes sense. Please note that before kernel 3.13, the kernel uses plist, but after 3.13 it uses rb_node for storing the list. If you want to exploit latest kernel, you will need to handle that.

This is actually where the bug is: there is a case where the waiter is still linked in the waiter list and the function returns. Please note that a kernel stack is completely separate from user stack. You can not influence kernel stack just by calling your own function in the userspace. You can manipulate kernel stack value (like the first example) by doing syscall.

If you don’t understand much about kernel, you can imagine a syscall is like a remote call to another machine: the execution on the other “machine” will use a separate stack from the one that you use in your local (user mode code). Note that this analogy doesn’t really hold when we talk about exploiting memory space.

A simpler bug

Before going into the detail about how the bug can be exploited in the kernel. I will present a much smaller and easier to understand userland code that has a similar bug. After you understand this, I will show how the kernel exploit works based on the same principle:

First, you will need to compile this in 32 bit mode, so the sizeof int is the same as the size of pointer (32 bit), don’t use any optimization when compiling.

gcc -m32 list1.c

Then run the resulting executable without any parameters it will print something like this:

$ ./mylist 
we will use pos: -1
Not a buggy function
Value = Alpha
Value = Beta
Value = --END OF LIST--
a buggy function, here is the location of value on stack 0xffd724a4
Value = Alpha
Value = Beta
Value = --END OF LIST--
location of buf[0] is 0xffd72488
location of buf[1] is 0xffd7248c
location of buf[2] is 0xffd72490
location of buf[3] is 0xffd72494
location of buf[4] is 0xffd72498
location of buf[5] is 0xffd7249c
location of buf[6] is 0xffd724a0
location of buf[7] is 0xffd724a4
location of buf[8] is 0xffd724a8
location of buf[9] is 0xffd724ac
Value = Alpha
Value = Beta
Value = --END OF LIST--

Notice the location of value on stack, which in this example is 0xffd724a4. Notice that it is the same as the address of buf[7]. Now run the test again, like this:

$./mylist 7 HACKED
we will use pos: 7
Not a buggy function
Value = Alpha
Value = Beta
Value = --END OF LIST--
a buggy function, here is the location of value on stack 0xffd3bd34
Value = Alpha
Value = Beta
Value = --END OF LIST--
Value = Alpha
Value = Beta
Value = HACKED

There is no assignment of the value “HACKED” to the list element, but it printed the word “HACKED”. Why this works? because we assign to the exact memory location in stack where “value” was stored. Also note that the location printed is now different because of ASLR, but because the position is the same in the stack, element number 7 is also relocated to the same address.

Now try out if you use other value than 7, also try a very small or very large value. You can also try this with stack protector on:

gcc -m32 -fstack-protector list1.c

The element that matched the address will be different (may be 7 becomes 8 or 6), but the exploit will still work if you adjust the element number with the matching address.

In this example, I made a very convenient function that makes the “exploit” easy (named a_function_to_exploit). In the real world, if we want to modify certain location in stack, we need to find a function that has a correct “depth” (that is: the stack size usage is at least the same as the function that we are trying to exploit), and we need to be able to manipulate the value on that stack depth. To understand about stack depth, you can comment the dummy_var1/dummy_var2/dummy_var3, compile, and see the stack address change. You can also see that if the function is optimized, certain variables are no longer in stack (moved to registers if possible).

Writing using list

Once you know how to manipulate an element of the list, you can write to certain memory address. On all exploits what you want to do is to write something to an address. To make this part short and to show my point, I will give an example for a simple linked list. If we have this:

Assume that we can control the content of n, we can write almost arbitrary value to arbitrary address. Lets assume that prev is in offset 4 of the node, and next is in offset 8. Please note that this structure assignment:

A->B = C;

is the same as:

*(A + offset_B) = C;

Lets assume we want to overwrite memory at location X with value Y. First prepare a fake node for the “next”, this fakenext is located at memory location Y (the location of the fake node is the value that we want to write), Of course this is limited to accessible memory space (so segmentation fault will not happen).

If we just want to change a value from 0 (for example: a variable containing number 0 if something is not allowed) to any non zero number (something is allowed), then we can use any number (we don’t even need a fake element, just a valid pointer to the “next” element).

n->next = fakenext;
n->prev = X-8

so when we call, this is what happens:

(n->next)->prev = n->prev;
(n->prev)->next = n->next

since n->next points to our fakenode

(fakenode)->prev = n->prev;
(n->prev)->next = fakenode

You can read more about this kind of list manipulation by searching google for heap exploits. For example, there are several articles about exploiting memory allocator in Phrack that uses list in the implementation (Vudo Malloc Tricks, Once upon a free, Advanced Doug lea’s malloc exploits and Malloc Des-Maleficarum).

These two things: that stack content can be manipulated, and that a manipulated list can be used to write to any address is the basis of the futex exploit.

On to the Kernel

Now lets go to where the bug is on the kernel.

You can also see the full code for futex_wait_requeue_pi().

In my simple userland code, there is a variable called instack that we want to manipulate, this time, we are interested in rt_waiter. In the case where futex requeue is called with uaddr1==uaddr2, the code path will cause q.rt_waiter to be NULL, but actually the waiter is still linked in the waiter list.

static int futex_requeue(u32 __user *uaddr1, unsigned int flags,u32 __user *uaddr2, int nr_wake, int nr_requeue,u32 *cmpval, int requeue_pi)

And the source code for futex_requeue()

Now we need a corresponding function for a_function_to_exploit. This syscall must be “deep” enough to touch the rt_waiter, so a syscall that doesn’t have a local variable, and doesn’t call other function is not usable.

First lets examine the function when we call it. From now on to show certain things, I will show how it looks in gdb that is connected to qemu for kernel debugging. Since I want to show things about towelroot, I am using qemu with ARM kernel. I am using this official guide for building Android kernel combined with stack overflow answer. When compiling the kernel, don’t forget to enable debug symbol. I created an Android 4.3 AVD, and started the emulator with this:


~/adt-bundle-linux/sdk/tools/emulator-arm -show-kernel -kernel arch/arm/boot/zImage -avd joeavd -no-boot-anim -no-skin -no-audio -no-window -logcat *:v -qemu -monitor telnet::4444,server -s

I can control the virtual machine via telnet localhost 444, and debug using gdb:

$ arm-eabi-gdb vmlinux

To connect and start debugging:

(gdb) target remote :1234

Why do I use GDB? Because this is the easiest way to get size of structure and to know what optimizations the compiler did. Lets break on the futex_wait_requeue_pi:

Breakpoint 6, futex_wait_requeue_pi (uaddr=0xb6e8be68, flags=1, val=0, abs_time=0x0, bitset=4294967295, uaddr2=0xb6e8be6c) at kernel/futex.c:2266
2266    {
(gdb) list
2261     * <0 - On error
2262     */
2263    static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2264                                     u32 val, ktime_t *abs_time, u32 bitset,
2265                                     u32 __user *uaddr2)
2266    {
2267            struct hrtimer_sleeper timeout, *to = NULL;
2268            struct rt_mutex_waiter rt_waiter;
2269            struct rt_mutex *pi_mutex = NULL;
2270            struct futex_hash_bucket *hb;
(gdb) list
2271            union futex_key key2 = FUTEX_KEY_INIT;
2272            struct futex_q q = futex_q_init;
2273            int res, ret;

We can see the structures

(gdb) ptype timeout
type = struct hrtimer_sleeper {
    struct hrtimer timer;
    struct task_struct *task;
}

(gdb) ptype rt_waiter
type = struct rt_mutex_waiter {
    struct plist_node list_entry;
    struct plist_node pi_list_entry;
    struct task_struct *task;
    struct rt_mutex *lock;
}

We can also check the backtrace of this function

(gdb) bt
#0  futex_wait_requeue_pi (uaddr=0xb6e8be68, flags=1, val=0, abs_time=0x0, bitset=4294967295, uaddr2=0xb6e8be6c) at kernel/futex.c:2266
#1  0xc0050e54 in do_futex (uaddr=0xb6e8be68, op=, val=0, timeout=, uaddr2=0xb6e8be6c, val2=0, val3=3068706412)
    at kernel/futex.c:2668
#2  0xc005100c in sys_futex (uaddr=0xb6e8be68, op=11, val=0, utime=, uaddr2=0xb6e8be6c, val3=0) at kernel/futex.c:2707
#3  0xc000d680 in ?? ()
#4  0xc000d680 in ?? ()

We can print out the size of the structures:

(gdb) print sizeof(rt_waiter)
$1 = 48
(gdb) print sizeof(timeout)
$2 = 56
(gdb) print sizeof(to)
$3 = 4
(gdb) print sizeof(q)
$4 = 56
(gdb) print sizeof(hb)
$5 = 4

We can look at the addresses of things, in this case, the variable pi_mutex is optimized as register, so we can’t access the variable address.

(gdb) print &key2
$6 = (union futex_key *) 0xd801de04
(gdb) print &timeout
$7 = (struct hrtimer_sleeper *) 0xd801de40
(gdb) print *&to
Can't take address of "to" which isn't an lvalue.
(gdb) print &rt_waiter
$8 = (struct rt_mutex_waiter *) 0xd801de10
(gdb) print &pi_mutex
Can't take address of "pi_mutex" which isn't an lvalue.
(gdb) print &hb
$9 = (struct futex_hash_bucket **) 0xd801ddf8
(gdb) print &q
$10 = (struct futex_q *) 0xd801de78

In the linux kernel source dode, there is a very convenient script that can measure stack usage of functions, unfortunately this doesn’t work very well on ARM, but here is an example output in i386.

objdump -d vmlinux | ./scripts/checkstack.pl


...
0xc10ff286 core_sys_select [vmlinux]:			296
0xc10ff4ac core_sys_select [vmlinux]:			296
...
0xc106a236 futex_wait_requeue_pi.constprop.21 [vmlinux]:212
0xc106a380 futex_wait_requeue_pi.constprop.21 [vmlinux]:212
...
0xc14a406b sys_recvfrom [vmlinux]:			180
0xc14a4165 sys_recvfrom [vmlinux]:			180
0xc14a4438 __sys_sendmmsg [vmlinux]:			180
0xc14a4524 __sys_sendmmsg [vmlinux]:			180
...

The numbers on the right shows the maximum stack usage that was accessed by that function. The rt_waiter is not the last variable on stack, so we don’t really need to go deeper than 212. The deeper the stack, the lower address value will be used, in our case, we can ignore the hashbucket, key2, q, that totals in 64 bytes. Any syscall that has a stack use of more than 212-64 is a candidate.

Learning from geohot’s exploit, he found that there are four very convenient functions that can be used, this is the fist value in towelroot modstring, sendmmsg, recvmmsg, sendmsg, and recvmsg (each corresponds to method 0-3 in his towelroot modstring).

Knowing the address of rt_waiter, lets see the kernel stack when towelroot calls sys_sendmmsg and look at the iovstack array.

(gdb) print &iovstack[0]
$17 = (struct iovec *) 0xd801ddf0
(gdb) print &iovstack[1]
$18 = (struct iovec *) 0xd801ddf8
(gdb) print &iovstack[2]
$19 = (struct iovec *) 0xd801de00
(gdb) print &iovstack[3]
$20 = (struct iovec *) 0xd801de08
(gdb) print &iovstack[4]
$21 = (struct iovec *) 0xd801de10

Look at that, the iovstack[4] is in the same address as rt_waiter

(gdb) print iovstack
$22 = {{iov_base = 0xa0000800, iov_len = 125}, {iov_base = 0xa0000800, iov_len = 125}, {iov_base = 0xa0000800, iov_len = 125}, {
    iov_base = 0xa0000800, iov_len = 125}, {iov_base = 0xa0000800, iov_len = 1050624}, {iov_base = 0xa0000800, iov_len = 125}, {
    iov_base = 0xa0000800, iov_len = 125}, {iov_base = 0xa0000800, iov_len = 125}}

And now lets see the iov as struct rt_mutex_waiter

(gdb) print *(struct rt_mutex_waiter*)&iovstack[4]
$23 = {list_entry = {prio = -1610610688, prio_list = {next = 0x100800, prev = 0xa0000800}, node_list = {next = 0x7d, prev = 0xa0000800}},
  pi_list_entry = {prio = 125, prio_list = {next = 0xa0000800, prev = 0x7d}, node_list = {next = 0xa0000800, prev = 0xa0000800}},
  task = 0xa0000800, lock = 0xa0000800}

Of course this function can return immediately when the data is received on the other side. So what towelroot do is this: create a thread that will accept a connection in localhost, after it accept()s it, it never reads the data, so the sendmmsg call will be just hanging there waiting for the data to be sent. So the receiver thread looks like this:

bind()
listen()
while (1) {
      s = accept();
      log("i have a client like hookers");
}

As you can see in the simplest list example, that a compiler optimization can cause the address to change slightly, so the other parameter in the modstring is the hit_iov, so in the towelroot code, it looks something like this:

for (i =0 ;i < 8; i++) {
iov[i].iov_base = (void *)0xa0000800;
iov[i].iov_len = 0x7d;
if (i==TARGET_IOV) {
iov[i].iov_len = 0x100800;
}
}

The other parameter related to iov is the align. I am not completely sure about this and when this is needed. From my observation, it sets all iov_len to 0x100800.

On the other thread, basically what towelroot does is this:

void sender_thread(){
setpriority(N);
connect(to_the_listener);
futex_wait_requeue_pi(...);
sendmmsg(...) ;
}

Unfortunately, having multi core can ruin things, so to make things safe, before starting, towelroot will set the process affinity so that this process will be run on only one core.

The detail of manipulating the waiter priority list is left to the reader (the objective is to write to a memory address) , but I can give you some pointers: to add a new waiter, use FUTEX_LOCK_PI, and to control where the item will be put, call setpriority prior to waiting. The baseline value is 120 (for nice value 0), so if you set priority 12 using setpriority, you will see the priority as 132 in the kernel land. The total line of plist.h and plist.c is only around 500 lines, and you only need to go to detail for plist_add and plist_del. Depending on what we want to overwrite, we don’t even need to be able to set to a specific value.

To modify the list, you will need multiple threads with different priorities. To be sure that the threads you started is really waiting inside a syscall (there will be time from creating the thread calling the syscall until it waits inside the syscall), you can use the trick that is used by towelroot: it reads the /proc/PID/task/TID/status of the Task with TID that you want to check. When the process is inside a syscall, the voluntary_ctxt_switches will keep on increasing (and the nonvoluntary_ctxt_switches will stay, but towelroot doesn’t check this). A voluntary context switch happens when a task is waiting inside a syscall.

Usually what people do when exploiting the kernel is to write to a function pointer. We can get the location of where these pointers are stored from reading /proc/kallsysms, or by looking at System.map generated when compiling the kernel. Both is usually not (easily) available in latest Android (this is one of the security mitigations introduced in Android 4.1). You may be able to get the address by recompiling an exact same kernel image using the same compiler and kernel configuration. On most PC distributions, you can find the symbols easily (via System.map and /proc/kallsyms is not restricted.

Assume that you can somehow get the address of a function pointer to overwrite, we can write a function that sets the current process credential to have root access and redirect so that our function is called instead of the original. But there is another way to change the process credential without writing any code that runs in kernel mode, just by writing to kernel memory. You can read the full presentation here, in the next part, I will only discuss the part needed to implement the exploit.

The Kernel Stack

Every thread is assigned a kernel stack space, and part of the stack space contains thread_info for that task. The stack address is different for every thread (the size is 8KB/thread in ARM) and you can not predict the address. So there will be a bunch of 8 KB stack blocks allocated for every thread. The thread_info is stored in the stack, in the lower address (stacks begins from top/high address). This thread_info contains information such as the pointer to task_struct. Inside a syscall, the task_struct for current thread is accessible by using the current macro:

#define get_current() (current_thread_info()->task)
#define current get_current()

In ARM, current_thread_info() is defined as:

#define THREAD_SIZE             8192
static inline struct thread_info *current_thread_info(void){
register unsigned long sp asm ("sp");
return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

Or if you want a constant number, the thread_info is located here $sp & 0xffffe000. Here is an example of task info when I am inside a syscall:

(gdb) print  *((struct thread_info*)(((uint32_t)$sp & 0xffffe000)))
$23 = {flags = 0, preempt_count = 0, addr_limit = 3204448256, task = 0xd839d000, exec_domain = 0xc047e9ec, cpu = 0, cpu_domain = 21, cpu_context = {
    r4 = 3626094784, r5 = 3627667456, r6 = 3225947936, r7 = 3626094784, r8 = 3561353216, r9 = 3563364352, sl = 3563364352, fp = 3563372460, 
    sp = 3563372408, pc = 3224755408, extra = {0, 0}}, syscall = 0, used_cp = "\000\000\000\000\000\000\000\000\000\000\001\001\000\000\000", 
  tp_value = 3066633984, crunchstate = {mvdx = {{0, 0} }, mvax = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, dspsc = {0, 0}}, 
  fpstate = {hard = {save = {0 }}, soft = {save = {0 }}}, vfpstate = {hard = {fpregs = {334529072224223236, 0, 
        0, 0, 0, 4740737484919406592, 4562254508917369340, 4724999426224703930, 0 }, fpexc = 1073741824, fpscr = 16, 
      fpinst = 3725516880, fpinst2 = 2816}}, restart_block = {fn = 0xc0028ca8 , {futex = {uaddr = 0x0, val = 0, flags = 0, 
        bitset = 0, time = 0, uaddr2 = 0x0}, nanosleep = {clockid = 0, rmtp = 0x0, expires = 0}, poll = {ufds = 0x0, nfds = 0, has_timeout = 0, 
        tv_sec = 0, tv_nsec = 0}}}}

Before continuing, you need to get a feeling of the memory mapping. This document doesn’t help much, but it gives an idea. Since every kernel can be compiled to have a different mapping, lets assume a common mapping for 32 bit ARM kernel:

  • a very low memory address (0x0-0x1000) is restricted for mapping (for security purpose)
  • address 0x1000-0xbf000000 is the user space
  • around 0xc0000000- 0xcffffff is where the kernel code location
  • area around 0xdxxxxxxx-0xfefffffe is where the kernel data is (stack and heap)
  • high memory ranges (0xfeffffff-0xffffffff) is reserved by the kernel.

The addr_limit is a nice target for overwrite. The default value for ARM is 3204448256 (0xbf000000), this value is checked in every operation in kernel that copy values from and to user space. You can read more about this in this post (Linux kernel user to kernel space range checks). The addr_limit is per task (every thread_info can have a different limit).

Area below addr_limit is considered to be a valid memory space that user space process can pass to kernel as parameter. Just to be clear here: if we modify addr_limit, it doesn’t mean that the user space can suddenly access memory at kernel space (for example, you can’t just dereference an absolute memory like this: *(uint32_t*)0xc0000000 to access kernel space from user space). The kernel can always read all the memory, so what this limit does is to make sure that when a user space gives a parameter to a syscall, the address given must be in user space. For example, kernel will not allow write(fd, addr, len) if addr is above addr_limit.

If we can somehow increase this limit, we can then read and modify kernel structures (using read/write syscall). Using a list manipulation, we can overwrite an address, and the location of addr_limit the one we want to overwrite.

Once we overwrite the addr_limit (in arm it is located at offset 8 in thread_info after flags and preempt_count), we can then (from userspace) read the address of the task_struct field, then from there, read the address of our credential (cred) field, then write/set our uid/gid to 0, and spawn a root shell (or do anything that you like, for example: just chown root/chmod suid certain file).

Kernel stack location

So basically we have two problems here: how to find the address to overwrite, and how to overwrite it. The part about “how to overwrite” is done by the list manipulation. The part about finding the address to overwrite: use other kernel vulnerability to leak kernel memory. There are a lot of bugs in the Linux kernel where it leaks memory to userspace (here is all of them in that category, there are 26 this year, and 194 in total), not all of these bugs can be used to leak the location of the stack.

Because the thread_info is always located at the beginning of stack, we can always find it if we know any address that is located in the stack, (just use addr & 0xffffe000). So we don’t really care about the exact leaked address. In the kernel space, there are a lot of code where a stack variable points to another variable. Just for an example, here is a code in futex.c that does this:

q.rt_waiter = &rt_waiter;
q.requeue_pi_key = &key2;

Both rt_waiter and key2 are located in the stack. If there is a code in the kernel that copies data to user space from uninitialized data on stack it, then will use whatever previous values that was on that stack, this is what we call an information leak. For a specific kernel version with a specific compiler we can get a reliable address, but with different kernel version and different compiler version (and optimization), most of the time this is not very reliable (it really depends on the previous usage of the stack and the stack layout created by the compiler). We can check for the leaked value, if we see a value above the addr_limit, what we get is a possible stack location.

Towelroot uses CVE-2013-2141 which is still in most Android kernel. You can check your kernel if it is affected by looking at the patch that corresponds to that bug (just check if info is initialized like this: struct siginfo info = {}). You can experiment a little bit to get a (mostly) reliable kernel stack address leak. This is the value that is printed by towelroot (“xxxx is a good number”). Please note that this is not 100% reliable, so sometimes towelroot will try to modify invalid address (it doesn’t seem to check if the address is above bf000000). Lets say we find the (possible) memory and name this POSSIBLE_STACK from now on.

Update: I was wrong, towelroot uses the stack address from the unlinked waiter address. The waiter is unlinked because of the tgkill() call. So the address should always be valid.

Overwrite

Ideally we want to be able to read the whole kernel space, but we can start small, increase our limit a little bit. You may have noticed several things by now: the rt_waiter is stored in the stack (lets say in location X), the addr_limit is also stored in stack (lets say Y), the X location is going to be always greater than Y for that thread. We know that the thread_info is always located at sp & 0xffffe000, so we have POSSIBLE_THREAD_INFO = (POSSIBLE_STACK & 0xffffe000). So if we can put the address of any rt_waiter from other tasks and write it to (POSSIBLE_THREAD_INFO + 8), we have increased the stack limit from bf000000 to some value (usually dxxxxxxx).

I am not entirely sure (since I don’t have a samsung S5), but it seems that the addr_limit is not always in offset 8, so towelroot have limit_offset to fix the address.

How to know if we have succesfully changed the address limit for a task? From inside that task, we can use the write syscall. For example, we can try: write(fd, (void *)0xc0000000, 4) . What we are trying to do is to write the content of the memory address to a file descriptor (you can replace 0xc000000 with any address above 0xbf000000). If we can do this successfuly, then we can continue because our limit has been changed.

On my experiment, the memory leak is sometimes very predictable (it leaks always a certain task kernel address, but not always). If we know exactly which thread address we modify, we can ask that thread to continue our work, otherwise, we need to ask all the threads that we have (for example by sending a signal): can you check if the address limit have been changed for you? If a thread can read the kernel memory address, then we know the address of that thread’s thread_info, we can then read and write to POSSIBLE_THREAD_INFO + 8. First thing that we want to do is to change *(POSSIBLE_THREAD_INFO + 8) = 0xffffffff. Now this thread can read and write to anywhere.

Here is an example where a thread’s addr_limit has been successfully changed to 0xffffffff:

(gdb) print  *((struct thread_info*)(((uint32_t)$sp & 0xffffe000)))
$22 = {flags = 0, preempt_count = 0, addr_limit = 4294967295, task = 0xd45d6000, exec_domain = 0xc047e9ec, cpu = 0, cpu_domain = 21, cpu_context = {
    r4 = 3561369728, r5 = 3562889216, r6 = 3225947936, r7 = 3561369728, r8 = 3562677248, r9 = 3069088276, sl = 3561955328, fp = 3561963004, 
    sp = 3561962952, pc = 3224755408, extra = {0, 0}}, syscall = 0, used_cp = "\000\000\000\000\000\000\000\000\000\000\001\001\000\000\000", 
  tp_value = 3061055232, crunchstate = {mvdx = {{0, 0} }, mvax = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, dspsc = {0, 0}}, 
  fpstate = {hard = {save = {0 }}, soft = {save = {0 }}}, vfpstate = {hard = {fpregs = {1067681969331808106, 0, 
        0, 0, 0, 4738224773140578304, 4562254508917369340, 4732617274506747052, 0 }, fpexc = 1073741824, fpscr = 16, 
      fpinst = 3725475920, fpinst2 = 2816}}, restart_block = {fn = 0xc0028ca8 , {futex = {uaddr = 0x0, val = 0, flags = 0, 
        bitset = 0, time = 0, uaddr2 = 0x0}, nanosleep = {clockid = 0, rmtp = 0x0, expires = 0}, poll = {ufds = 0x0, nfds = 0, has_timeout = 0, 
        tv_sec = 0, tv_nsec = 0}}}}

Once you can read/write anywhere, you can do anything, its game over. First you may want to fix the plist so that it will not crash (something that was not done by towelroot v1), although sometimes in towelroot v3, it stops because it was unable to fix the list even though it can do the rooting process. Even though you can read/write using file, to make it easy you can use pipe, and write/read to/from that pipe.

If we have a pipe, with rfd as read descriptor in the side of the pipe and wfd as the write descriptor, we can do this: To read a memory from kernel: do a write(wfd, KERNEL_ADDR, size), and read the result in read(rfd, LOCAL_ADDRESS, size). To write to kernel memory: do a write(wfd, LOCAL_ADDRESS, size), and then read(rfd, KERNEL_ADDRESS, size).

If you want to play around without creating exploit, you can also try out the addr_limit by setting the value manually in your debugger.

The last modstring in towelroot is temp_root which is not related to the exploit itself, it only creates temporary root for devices that have non writeable /system.

So thats all there is to it. I have shown you where the bug is, which syscall that you can use to manipulate the stack, how to write to arbitrary address (although not in detail, but with enough pointers), what to write there, and what to do after you write there.

Implementing a web server in a single printf() call

A guy just forwarded a joke that most of us will already know Jeff Dean Facts (also here and here). Everytime I read that list, this part stands out:

Jeff Dean once implemented a web server in a single printf() call. Other engineers added thousands of lines of explanatory comments but still don’t understand exactly how it works. Today that program is the front-end to Google Search.

It is really possible to implement a web server using a single printf call, but I haven’t found anyone doing it. So this time after reading the list, I decided to implement it. So here is the code, a pure single printf call, without any extra variables or macros (don’t worry, I will explain how to this code works)

#include <stdio.h>

int main(int argc, char *argv[])
{
 printf("%*c%hn%*c%hn"
  "\xeb\x3d\x48\x54\x54\x50\x2f\x31\x2e\x30\x20\x32"
  "\x30\x30\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d"
  "\x74\x79\x70\x65\x3a\x74\x65\x78\x74\x2f\x68\x74"
  "\x6d\x6c\x0d\x0a\x0d\x0a\x3c\x68\x31\x3e\x48\x65"
  "\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x3c\x2f"
  "\x68\x31\x3e\x4c\x8d\x2d\xbc\xff\xff\xff\x48\x89"
  "\xe3\x48\x83\xeb\x10\x48\x31\xc0\x50\x66\xb8\x1f"
  "\x90\xc1\xe0\x10\xb0\x02\x50\x31\xd2\x31\xf6\xff"
  "\xc6\x89\xf7\xff\xc7\x31\xc0\xb0\x29\x0f\x05\x49"
  "\x89\xc2\x31\xd2\xb2\x10\x48\x89\xde\x89\xc7\x31"
  "\xc0\xb0\x31\x0f\x05\x31\xc0\xb0\x05\x89\xc6\x4c"
  "\x89\xd0\x89\xc7\x31\xc0\xb0\x32\x0f\x05\x31\xd2"
  "\x31\xf6\x4c\x89\xd0\x89\xc7\x31\xc0\xb0\x2b\x0f"
  "\x05\x49\x89\xc4\x48\x31\xd2\xb2\x3d\x4c\x89\xee"
  "\x4c\x89\xe7\x31\xc0\xff\xc0\x0f\x05\x31\xf6\xff"
  "\xc6\xff\xc6\x4c\x89\xe7\x31\xc0\xb0\x30\x0f\x05"
  "\x4c\x89\xe7\x31\xc0\xb0\x03\x0f\x05\xeb\xc3",
  ((((unsigned long int)0x4005c8 + 12) >> 16) & 0xffff), 
  0, 0x00000000006007D8 + 2, 
  (((unsigned long int)0x4005c8 + 12) & 0xffff)-
  ((((unsigned long int)0x4005c8 + 12) >> 16) & 0xffff), 
  0, 0x00000000006007D8 );
}

This code only works on a Linux AMD64 bit system, with a particular compiler (gcc version 4.8.2 (Debian 4.8.2-16) ) And to compile it:

gcc -g web1.c -O webserver

As some of you may have guessed: I cheated by using a special format string . That code may not run on your machine because I have hardcoded two addresses.

The following version is a little bit more user friendly (easier to change), but you are still going to need to change 2 values: FUNCTION_ADDR and DESTADDR which I will explain later:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define FUNCTION_ADDR ((uint64_t)0x4005c8 + 12)
#define DESTADDR 0x00000000006007D8
#define a (FUNCTION_ADDR & 0xffff)
#define b ((FUNCTION_ADDR >> 16) & 0xffff)

int main(int argc, char *argv[])
{
	printf("%*c%hn%*c%hn"
		"\xeb\x3d\x48\x54\x54\x50\x2f\x31\x2e\x30\x20\x32"
		"\x30\x30\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d"
		"\x74\x79\x70\x65\x3a\x74\x65\x78\x74\x2f\x68\x74"
		"\x6d\x6c\x0d\x0a\x0d\x0a\x3c\x68\x31\x3e\x48\x65"
		"\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x3c\x2f"
		"\x68\x31\x3e\x4c\x8d\x2d\xbc\xff\xff\xff\x48\x89"
		"\xe3\x48\x83\xeb\x10\x48\x31\xc0\x50\x66\xb8\x1f"
		"\x90\xc1\xe0\x10\xb0\x02\x50\x31\xd2\x31\xf6\xff"
		"\xc6\x89\xf7\xff\xc7\x31\xc0\xb0\x29\x0f\x05\x49"
		"\x89\xc2\x31\xd2\xb2\x10\x48\x89\xde\x89\xc7\x31"
		"\xc0\xb0\x31\x0f\x05\x31\xc0\xb0\x05\x89\xc6\x4c"
		"\x89\xd0\x89\xc7\x31\xc0\xb0\x32\x0f\x05\x31\xd2"
		"\x31\xf6\x4c\x89\xd0\x89\xc7\x31\xc0\xb0\x2b\x0f"
		"\x05\x49\x89\xc4\x48\x31\xd2\xb2\x3d\x4c\x89\xee"
		"\x4c\x89\xe7\x31\xc0\xff\xc0\x0f\x05\x31\xf6\xff"
		"\xc6\xff\xc6\x4c\x89\xe7\x31\xc0\xb0\x30\x0f\x05"
		"\x4c\x89\xe7\x31\xc0\xb0\x03\x0f\x05\xeb\xc3"
	, b, 0, DESTADDR + 2, a-b, 0, DESTADDR );
}

I will explain how the code works through a series of short C codes. The first one is a code that will explain how that we can start another code without function call. See this simple code:

#include <stdlib.h>
#include <stdio.h>

#define ADDR 0x00000000600720

void hello()
{
        printf("hello world\n");
}

int main(int argc, char *argv[])
{
        (*((unsigned long int*)ADDR))= (unsigned long int)hello;
}

You can compile it, but it many not run on your system. You need to do these steps:

1. Compile the code:

gcc run-finalizer.c -o run-finalizer

2. Examine the address of fini_array

objdump -h -j .fini_array run-finalizer

And find the VMA of it:

run-finalizer:     file format elf64-x86-64
Sections:
Idx Name          Size      VMA               LMA               File off  Algn
 18 .fini_array   00000008  0000000000600720  0000000000600720  00000720  2**3
                  CONTENTS, ALLOC, LOAD, DATA

Note that you need a recent GCC to do this, older version of gcc uses different mechanism of storing finalizers.

3. Change the value of ADDR on the code to the correct address

4. Compile the code again

5. Run it

and now you will see “hello world” printed to your screen. How does this work exactly?:

According to Chapter 11 of Linux Standard Base Core Specification 3.1

.fini_array
This section holds an array of function pointers that contributes to a single termination array for the executable or shared object containing the section.

We are overwriting the array so that our hello function is called instead of the default handler. If you are trying to compile the webserver code, the value of ADDR is obtained the same way (using objdump).

Ok, now we know how to execute a function by overriding a certain address, we need to know how we can overwrite an address using printf. You can find many tutorials on how to exploit format string bugs, but I will try give a short explanation.

The printf function has this feature that enables us to know how many characters has been printed using the “%n” format:

#include <stdio.h>
int main(){
        int count;
        printf("AB%n", &count);
        printf("\n%d characters printed\n", count);
}

You will see that the output is:

AB
2 characters printed

Of course we can put any address to the count pointer to overwrite that address. But to overide an address with a large value we need to print a large amount of text. Fortunately there is another format string “%hn” that works on short instead of int. We can overwrite the value 2 bytes at a time to form the 4 byte value that we want.

Lets try to use two printf calls to put a¡ value that we want (in this case the pointer to function “hello”) to the fini_array:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define FUNCTION_ADDR ((uint64_t)hello)
#define DESTADDR 0x0000000000600948

void hello()
{
	printf("\n\n\n\nhello world\n\n");
}

int main(int argc, char *argv[])
{
	short a= FUNCTION_ADDR & 0xffff;
	short b = (FUNCTION_ADDR >> 16) & 0xffff;
	printf("a = %04x b = %04x\n", a, b)
        uint64_t *p = (uint64_t*)DESTADDR;
        printf("before: %08lx\n", *p);
	printf("%*c%hn", b, 0, DESTADDR + 2 );
        printf("after1: %08lx\n", *p); 
	printf("%*c%hn", a, 0, DESTADDR);
        printf("after2: %08lx\n", *p);
	return 0;
}

The important lines are:

	short a= FUNCTION_ADDR & 0xffff;
	short b = (FUNCTION_ADDR >> 16) & 0xffff;
	printf("%*c%hn", b, 0, DESTADDR + 2 );
	printf("%*c%hn", a, 0, DESTADDR);

The a and b are just halves of the function address, we can construct a string of length a and b to be given to printf, but I chose to use the “%*” formatting which will control the length of the output through parameter.

For example, this code:

   printf("%*c", 10, 'A');

Will print 9 spaces followed by A, so in total, 10 characters will be printed.

If we want to use just one printf, we need to take account that b bytes have been printed, and we need to print another b-a bytes (the counter is accumulative).

  printf("%*c%hn%*c%hn", b, 0, DESTADDR + 2, b-a, 0, DESTADDR );

Currently we are using the “hello” function to call, but we can call any function (or any address). I have written a shellcode that acts as a web server that just prints “Hello world”. This is the shell code that I made:

unsigned char hello[] = 
		"\xeb\x3d\x48\x54\x54\x50\x2f\x31\x2e\x30\x20\x32"
		"\x30\x30\x0d\x0a\x43\x6f\x6e\x74\x65\x6e\x74\x2d"
		"\x74\x79\x70\x65\x3a\x74\x65\x78\x74\x2f\x68\x74"
		"\x6d\x6c\x0d\x0a\x0d\x0a\x3c\x68\x31\x3e\x48\x65"
		"\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64\x21\x3c\x2f"
		"\x68\x31\x3e\x4c\x8d\x2d\xbc\xff\xff\xff\x48\x89"
		"\xe3\x48\x83\xeb\x10\x48\x31\xc0\x50\x66\xb8\x1f"
		"\x90\xc1\xe0\x10\xb0\x02\x50\x31\xd2\x31\xf6\xff"
		"\xc6\x89\xf7\xff\xc7\x31\xc0\xb0\x29\x0f\x05\x49"
		"\x89\xc2\x31\xd2\xb2\x10\x48\x89\xde\x89\xc7\x31"
		"\xc0\xb0\x31\x0f\x05\x31\xc0\xb0\x05\x89\xc6\x4c"
		"\x89\xd0\x89\xc7\x31\xc0\xb0\x32\x0f\x05\x31\xd2"
		"\x31\xf6\x4c\x89\xd0\x89\xc7\x31\xc0\xb0\x2b\x0f"
		"\x05\x49\x89\xc4\x48\x31\xd2\xb2\x3d\x4c\x89\xee"
		"\x4c\x89\xe7\x31\xc0\xff\xc0\x0f\x05\x31\xf6\xff"
		"\xc6\xff\xc6\x4c\x89\xe7\x31\xc0\xb0\x30\x0f\x05"
		"\x4c\x89\xe7\x31\xc0\xb0\x03\x0f\x05\xeb\xc3";

If we remove the function hello and insert that shell code, that code will be called.

That code is just a string, so we can append it to the “%*c%hn%*c%hn” format string. This string is unnamed, so we will need to find the address after we compile it. To obtain the address, we need to compile the code, then disassemble it:

objdump -d webserver

00000000004004fd <main>:
  4004fd:	55                   	push   %rbp
  4004fe:	48 89 e5             	mov    %rsp,%rbp
  400501:	48 83 ec 20          	sub    $0x20,%rsp
  400505:	89 7d fc             	mov    %edi,-0x4(%rbp)
  400508:	48 89 75 f0          	mov    %rsi,-0x10(%rbp)
  40050c:	c7 04 24 d8 07 60 00 	movl   $0x6007d8,(%rsp)
  400513:	41 b9 00 00 00 00    	mov    $0x0,%r9d
  400519:	41 b8 94 05 00 00    	mov    $0x594,%r8d
  40051f:	b9 da 07 60 00       	mov    $0x6007da,%ecx
  400524:	ba 00 00 00 00       	mov    $0x0,%edx
  400529:	be 40 00 00 00       	mov    $0x40,%esi
  40052e:	bf c8 05 40 00       	mov    $0x4005c8,%edi
  400533:	b8 00 00 00 00       	mov    $0x0,%eax
  400538:	e8 a3 fe ff ff       	callq  4003e0 <printf@plt>
  40053d:	c9                   	leaveq 
  40053e:	c3                   	retq   
  40053f:	90                   	nop

We only need to care about this line:

mov    $0x4005c8,%edi

That is the address that we need in:

#define FUNCTION_ADDR ((uint64_t)0x4005c8 + 12)

The +12 is needed because our shell code starts after the string “%*c%hn%*c%hn” which is 12 characters long.

If you are curious about the shell code, it was created from the following C code.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<signal.h>
#include<fcntl.h>

int main(int argc, char *argv[])
{
	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	struct sockaddr_in serv_addr;
	bzero((char *)&serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = INADDR_ANY;
        serv_addr.sin_port = htons(8080);
	bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
	listen(sockfd, 5);
	while (1) {
		int cfd  = accept(sockfd, 0, 0);
		char *s = "HTTP/1.0 200\r\nContent-type:text/html\r\n\r\n<h1>Hello world!</h1>"; 
		if (fork()==0) {
			write(cfd, s, strlen(s));
			shutdown(cfd, SHUT_RDWR);
			close(cfd);
		}	
	}

	return 0;
}

I have done an extra effort (although it is not really necessary in this case) to remove all NUL character from the shell code (since I couldn’t find one for X86-64 in the Shellcodes database).

Jeff Dean once implemented a web server in a single printf() call. Other engineers added thousands of lines of explanatory comments but still don’t understand exactly how it works. Today that program is the front-end to Google Search.

It is left as an exercise for the reader to scale the web server to able to handle Google search load.

Source codes for this post is available at https://github.com/yohanes/printf-webserver

For people who thinks that this is useless: yes it is useless. I just happen to like this challenge, and it has refreshed my memory and knowledge for the following topics: shell code writing (haven’t done this in years), AMD64 assembly (calling convention, preserved registers, etc), syscalls, objdump, fini_array (last time I checked, gcc still used .dtors), printf format exploiting, gdb tricks (like writing memory block to file), and low level socket code (I have been using boost’s for the past few years).

Update: Ubuntu adds a security feature that provides a read-only relocation table area in the final ELF. To be able to run the examples in ubuntu, add this in the command line when compiling

-Wl,-z,norelro

e.g:

gcc -Wl,-z,norelro test.c

Raspberry Pi for Out of Band Linux PC management

Just a day before I left to Indonesia for my brother’s wedding, I got worried about my headless Linux PC server: it may freeze when I left it. It happened before because of kernel panic and hardware error, it can happen again. I want to be able to reset the PC in case of errors and to power it down in case the error was not recoverable (for example last year my disk drive went bad).

Just a note before reading this: in case you just want to turn on or off a PC using raspberry PI: just use wake on LAN (WOL) to turn on your PC and SSH access to turn it off. Wake on LAN works most of the time, but it can not handle a PC that is not responding.

I soldered 2 optocouplers that I have (4N25) to a small perfboard with a pin header. Then I use solderless breadboard cables to connect the board to Raspberry Pi, and to the PC power and reset button (so I can manually turn on/off using the power/reset button on the PC).

4n25

Watch carefully about the + and – on the motherboard (PW is for power, and RES is for reset, note the polarity is important for the optocoupler, on the picture above: Red goes to + and Black goes to -):

I could just have used one optocoupler to connect to the power button (the reset is not really necessary, because we can turn off and on the PC again to reset), but I just want to use the extra 4N25 that I have (it’s really cheap, 5.5 baht or around 17 cents USD).

To reset the PC, I just set the GPIO pin to high for about one second, then set it low again. To power up the PC, I set the GPIO pin to high for about 5 seconds, and set it low again (the same can be used to forcefully power down the PC).

Resetting and powering the PC is easy, the next task is to know what happened if the PC crashed. To do this, I need a serial connection. If my PC has a serial port and I have a USB to serial cable, then everything will be much easier, but since I don’t have a USB to serial cable, and my PC doesn’t have a serial port on the back, it gets a bit complicated.

I still have a small board based on MAX3232CPE to convert from 3.3V serial to 5.0 V, so I plugged that board to Raspberry Pi and connected it directly to the PC motherboard. This page helped me in finding the pin names (I only need to connect RX, TX and GND).

mb

On the Raspberry side, I need to set up so that it will not use the serial port for kernel output and log in. You can follow the guide here.

On the PC side, I need to activate serial output in three places: to accept login (getty), to get the kernel output (kernel parameters in grub), and in grub itself (to show the boot selection dialog). This guide for Debian works for me, but I was not able to see the GRUB output on screen when I connected my screen (I can only see the output on my serial console, but this was not a problem for me).

I experimented a little bit with SGABios Hoping that I would be able to see BIOS output from my serial port. It didn’t work as expected. I can not see the initial BIOS screen, and I can not send a key to enter BIOS setting, but If I connect a keyboard and press a button to enter the BIOS, I can see the BIOS menu via serial port and I can interact with it.

Here are the steps that I tried to get the BIOS serial output: I downloaded the BIOS for my motherboard (an AWARD BIOS). Then on a windows machine, I modified the BIOS using CBROM cbrom bios.bin /isa sgabios.bin. Then I flashed the BIOS from Linux using Flashrom.

I didn’t solve the BIOS problem due to time constraint. There are several solutions that I can think of to solve this: one is to use CoreBoot (but unfortunately my motherboard is not supported by coreboot), another one is to try to do more hacking on the BIOS (maybe removing the VGA ROM to force the output to serial port) and the other one is to simulate a keypress to enter BIOS. The first two methods may not be portable across BIOS, but the last one should be portable. The key simulation can be done by simulating a PS2 device (using bitbanging on Raspberry Pi), or USB HID device. A super simple USB HID device can be made by using V-USB library (you can see this as an example).

Just a few hours before I left, I have an idea to connect a temperature sensor just to see if the temperature around the PC case is too high. We are entering the summer here in Chiang Mai and the outside temperature is getting higher every day (from November to beginning of February, the temperature was around 8-20 Celcius, and now it is around 17-37 Celcius). It was quite easy to add the temperature sensor, I just use the guide and driver from adafruit. Next time I may add an infrared LED on the Raspberry Pi to turn on the Air Conditioner when it gets really hot.

Having everything setup: nothing happened while I was away. The PC was running nicely (and I can access the PC via SSH and the serial console).