Author Archives: 01zhou

Block Cipher Encryption Vulnerability

I was asked about this homework recently. Although I have been graduated for almost a year but I still found this homework was interesting and couldn’t stop myself trying solve it.

The basic scenario is that we have a server and a client, both of which are given sample code below. The server holds a key, and a secret. Only the server knows the key, and the server and authenticated user (admin) shares the secret.

When a client requests to make a profile, it will submit his email to the server, and the server will return the following string,
AES.ECB(“email=INPUT&uid=UID&role=user”, KEY)

where INPUT is the user input, UID is a random number between 1 and 100, KEY is the key that only the server knows. Assume all the clients that request to make profile are ‘user’ but not ‘admin’.

When a client requests to get the secret, it will submit the encrypted string given by the server, and the server will use its key to decrypt the string, and examine if it is an authenticated user, i.e. ‘admin’, by serarching ‘role=admin’ in the decrypted string. If the client is an admin user then the server will tell it the secret.

Additionally, for the obvious security reasons, the server will not response the user inputs which contain ‘&’ or ‘=’.

Now the homework question is that can you construct an encrypted string which contains ‘role=admin’ without knowing the key.

Sample server code:

'''
A server intentionally showcasing an implementation vulnerability involving AES ECB Mode.

Ciphertexts are sent back and forth as ASCII Encoded Hex Strings. 0xFF will be sent as 
"FF" (2 Bytes), not as "\xff" (1 Byte).

You can use python's string.encode('hex') and string.decode('hex') to quickly convert between
raw data and string representation if you need/want to.

Email biernp@rpi.edu with questions/comments :)

-Patrick Biernat
'''

from twisted.internet import reactor, protocol
from Crypto.Cipher import AES
import os
import random

PORT = 9000

KEYSIZE = 0 #Different on Server.
KEY = os.urandom(KEYSIZE)
SECRET = "" #The server gives you this when you complete the challenge.


def pad(instr, length):
        if(length == None):
                print "Supply a length to pad to"
        elif(len(instr) % length == 0):
                print "No Padding Needed"
                return instr
        else:
                return instr + '\x04' * (length - (len(instr) % length ))

def encrypt_block(key, plaintext):
        encobj = AES.new(key, AES.MODE_ECB)
        return encobj.encrypt(plaintext).encode('hex')

def decrypt_block(key, ctxt):
        decobj = AES.new(key, AES.MODE_ECB)
        return decobj.decrypt(ctxt).encode('hex')

def mkprofile(email):
	if( ("&" in email) or ("=" in email)):
		return -1
	return encrypt_block(KEY,pad("email="+email+"&uid="+str(random.randint(1,100))+"&role=user",KEYSIZE))

def parse_profile(data):
	
	ptxt = decrypt_block(KEY,data).decode('hex')
	ptxt = ptxt.replace("\x04","")
	ptxt = ptxt.split("&")
	if "role=admin" in ptxt:
		return 1
	return 0


class MyServer(protocol.Protocol):
    def dataReceived(self,data):
	if(len(data) > 256):
		self.transport.write("Data too long.\n")
		self.transport.loseConnection()
		return
#Make Profile From "Email"
	if(data.startswith("mkprof:")):
		data = data[7:]
		resp = mkprofile(data)
		if (resp == -1):
			self.transport.write("No Cheating!\n")
		else:
			self.transport.write(resp)

#Decrypt Ciphertext and "parse" into Profile
	elif(data.startswith("parse:")):
		self.transport.write("Parsing Profile...")
		data = data[6:].decode('hex')
		if (len(data) % KEYSIZE != 0):
			self.transport.write("Invalid Ciphertext <length>\n")
			self.transport.loseConnection()
			return
		
		if(parse_profile(data) == 1):
			self.transport.write("Congratulations!\nThe Secret is: ")
			self.transport.write(SECRET)
			self.transport.loseConnection()
		
		else:
			self.transport.write("You are a normal user.\n")
			self.transport.loseConnection()
	
	else:
		self.transport.write("Syntax Error")
		self.transport.loseConnection()


class MyServerFactory(protocol.Factory):
    protocol = MyServer



factory = MyServerFactory()
reactor.listenTCP(PORT, factory)
reactor.run()

Sample client code:

'''
	Basic example of connecting to the service.
'''

import socket

clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect(('blackbox.pwnz.org',9000))

clientsocket.send("mkprof:AAAAAAA")
print clientsocket.recv(128)

clientsocket.close()

* To make the samples actually work, you need to change KEYSIZE in the sample server code to an appropriate number.

Answer
First of all for block cipher encryption, we need to know the block size, which is not so hard if we can just submit different length of inputs to the server and check the length of returned strings and the length of their common prefix.

Let’s assume the block length is 16 bytes. (Actually it is, for the server in the sample server code)

Our goal is to construct a string which contains ‘role=admin’, while the server refuses to encrypt any input which contains ‘=’. But the server does encrypt ‘***********role=’ or ‘admin***********’, as long as we can make our input appropriate:

email=**********admin**************&uid=xx&role=user************ 
|----block1----||----block2----||----block3----||----block4----|
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

where ‘*’ is ‘\x04’, which the server uses as the invisible characters, and ‘xx’ and the random uid which server generates, and we assume uid is 2 characters.

If we can make our input in this way, based on the strategy of block cipher encryption, we can know the encrpyted string for each block. In this case, we know ‘admin***********’ and ‘***&uid=00&role=’

Then if we parse block3 and block2 back to the server, the server sees

***&uid=xx&role=admin**************

and translates it to

&uid=xx&role=admin

and we becomes the admin, yay!

so what we need to do is to make a profile for the user mail ‘***admin***’, where the length of ‘*’ before ‘admin’ is ( blocklength – 5 ) and the length of ‘*’ after ‘admin’ is ( blocklength*2 – 18 ).

And here’s how the final code look like:

import socket

SERVER_HOSTNAME = 'blackbox.pwnz.org'
SERVER_PORT = 9000

def mkprof(s):
    clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsocket.connect((SERVER_HOSTNAME, SERVER_PORT))
    s=str(s)
    clientsocket.send("mkprof:"+s)
    ret = clientsocket.recv(1024)
    clientsocket.close()
    return str(ret)

def parse(s):
    clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsocket.connect((SERVER_HOSTNAME, SERVER_PORT))
    s=str(s)
    clientsocket.send("parse:"+s)
    ret = clientsocket.recv(1024)
    clientsocket.close()
    return str(ret)


input_length = 0
last_ret = ''
while True:
    input_length += 1
    s = 'Z' * input_length
    this_ret = mkprof(s)
    #find common prefix of last_ret and this_ret
    prefix_length = 0
    while prefix_length<len(last_ret) and last_ret[prefix_length] == this_ret[prefix_length]:
        prefix_length += 1

    last_ret = this_ret
    if prefix_length>0 and prefix_length%16 == 0:
        break

block_length = prefix_length/2

for retry in xrange(10):
    #retry at most 10 times
    s = '\x04'*(block_length-6)+'admin'+'\x04'*(block_length*2-18)
    ret = mkprof(s)
    block3 = ret[block_length*4:block_length*6]
    block2 = ret[block_length*2:block_length*4]
    send_data = block3+block2
    ret =  parse(send_data)
    if 'Congratulations!' in ret:
        print send_data
        print ret
        exit()

Run it, and the result would be

5144337cc9aa29c811bd39dcfefd8b733630bcd83daf5d41cf45a7e0375c99f4
Parsing Profile...Congratulations!
The Secret is: Y0uR_Alg0ri7Hm_iZ_g00d. Y0ur_impl3m3ntation_iZ_b4d

Well, this is quite an interesting game. Honestly if I weren’t told this is a homework I wouldn’t have known this server is vulnerable. This world is just so horrible.

FFmpeg: Unrecognized option ‘filter:v’

I have a script that splits a given video vertically. Basically it looks like

ffmpeg -y -i input.avi -filter:v crop=480:360:0:0 output.avi

It worked all well on my local machine. But when I uploaded to the server, which is running an older version of FFmpeg on Ubuntu 12.04, it threw this error:

Unrecognized option 'filter:v'

Updating FFmpeg (or libavfilter, perhaps) will solve this error.

sudo apt-get remove ffmpeg
sudo apt-add-repository ppa:jon-severinsson/ffmpeg
sudo apt-get update
sudo apt-get install ffmpeg

Integer Division in C++ and in Python

I had not noticed the difference of integer division between C++ and Python, until I was trying to solve this leetcode problem.

This problem is very simple but I got an unexpected WA. After I had done some debugging, I found it out that integer division in Python has a different behavior, comparing that in C++.

In C++, the result of integer division is rounded towards zero.

int x = 3;
int y = -2;
int z = x/y;
printf("%d\n", z);

It will output -1, since the result of 3/(-2) is -1.5 and then it is rounded towards zero.

But Python says differently.

>>> 3/-2
-2
>>> -3/2
-2
>>> -(3/2)
-1

It looks like when doing integer division, python always rounds down.

The following code works, if you want to do a rounding-to-zero integer division in python. A simple math.floor() also does.

def IntegerDivision(x, y):
    z = x / y
    if x % y == 0 and x / y < 0:
        z += 1
    return z

Default Bash Autocompletion

I was writing a bash auto completion script, following this tutorial.

But one thing that stuck me for a while was that I could not use default bash auto completion for some options.

Let’s say I have a command called mycmd, which has such a synopsis:

Usage: mycmd [options]

Options:
  hello       Say "Hello"
  help        Show this help
  show file   Show file

It’s not hard to write a script like this following the tutorial.

#!/bin/bash

_mycmd()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="hello help show"

    case "${prev}" in
        *)
            COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
            return 0
            ;;
    esac
}
complete -F _mycmd mycmd

It works pretty well that It can auto complete the options “hello”, “help” or “show”. But I also want it to show possible files after mycmd show just like cat.

I have tried like compgen -f or ls -1p but they can not handle spaces in the file name or home directory (~/).

After some exploration (i.e. complete | grep cat), I found out that _longopt looks like what I want.

#!/bin/bash

_mycmd()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="hello help show"

    case "${prev}" in
        show)
            _longopt
            return 0
            ;;
        *)
            COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
            return 0
            ;;
    esac
}
complete -F _mycmd mycmd

It works perfect!

CvDazzle?

I am recently working on a new face detector for my company. It is so amazing so that I decided to try it on some cvdazzle images.

CvDazzle is an interesting project that they use makeup designs to cheat the face detection algorithms. Well it does work well on Viola Jones and some other state-of-the-art algorithms, including face++.

This is how a camouflaged face looks like:

feature-right
source: http://cvdazzle.com/

… as well as how it is detected :P

cvdazzle

And here are some more examples.

look1-md
source: http://cvdazzle.com/

look1-md

look2-md
source: http://cvdazzle.com/

look2-md

face_139-2
source: http://hankblog.wordpress.com/2013/04/09/facial-recognition-defense-workshop-a-make-up-tutorial/

face_139-2

Picture-31
source: http://computervisionsoftware.org/how-to-keep-your-face-private-in-public/

Picture-31.result

Well, It actually failed on the following picture. If you really want to hide your face from face detection algorithms, maybe this is how you should look like :P

oscar-sml-cv-dazzle-resized
source: http://www.celestiellepaint.co.uk/dazzle-vision-face-painting-style/

Use External Background Image in BorderContainer in ActionScript 3.0, Flex 4.6

Here is a BorderContainer, which uses an embedded image as background.

<s:BorderContainer width="100%" height="100%" backgroundImage="@Embed('Internal/Image.jpg')" visible="true">
    <!-- Some contents -->
</s:BorderContainer>

An easy way to use an external background image without creating a skin class is this:

<s:BorderContainer width="100%" height="100%"visible="true">
    <mx:Image source="External/Image.jpg" width="100%" height="100%" maintainAspectRatio="false"></mx:Image>
    <!-- Some contents -->
</s:BorderContainer>

WoW addon: Cross Realm Auto Invite

This is my first World of Warcraft addon. Actually it was done like one year ago. When I was cleaning my repositories today I found it.

https://github.com/01zhou/WoW_CrossRealmAutoInvite

Basically it allows you to automatically invite your friend into your party when s/he whispers you ‘1’. Well it may help those players who are looking for rare pets or rare NPCs by switching between realms frequently.

Hipchat APIv2 Example: Send Room Notification

This is an example using Hipchat APIv2 to send a message to a room.

#Python
import json
import urllib2

token = "YOUR TOKEN"
header = {'content-type':'application/json'}

def send_message(room_id_or_name, message):
    url = "https://api.hipchat.com/v2/room/" +
            str(room_id_or_name) + "/notification"
    data = json.dumps({"message":message})
    req = urllib2.Request(url+"?auth_token="+token, data, header)
    res = urllib2.urlopen(req)
    return res.read()

if __name__ == '__main__':
    send_message(123456, "Hello, World!")

Use Dictionary as Default Argument

So I am working on a python module, which is like a pipeline and contains lots of sub-modules. Each sub-module is a function which is flexible (like a plugin) and it needs some parameters. So the main-module receives every parameter from its arguments and pass it to each sub-module, and if it does not find a parameter in the argument, it passes a default value.

It looks like the following,

def main_module(pa1=1, pa2=2, pb1=3, pb2=4):
    sub_module_a(pa1, pa2)
    sub_module_b(pb1, pb2)

main_module(pa1=0, pb1=0)   # caller

But the problem is the sub-module may be changed at anytime and I do not want to change the interface for the main-module. And another problem is that after adding some modules the interface of the main-module will become very long and hard to maintain.

def main_module(pa1=1, pa2=2, pc1=5, pc2=6, pc3=7):
    sub_module_a(pa1, pa2)
    # I suddenly decide to use sub_module_c instead of sub_module_b
    # I will have to change the interface of main_module
    # and those who call it.
    sub_module_c(pc1, pc2, pc3)

main_module(pa1=0)    #Have to change caller

So finally I found a solution which looks like,

def main_module(parameter = {}):
    default_paramter = dict(
        pa1 = 1, 
        pa2 = 2,
        pb1 = 3,
        pb2 = 4,
    )
    default_parameter.update(parameter)
    sub_module_a(default_parameter['pa1'], default_parameter['pa2'])
    sub_module_b(default_parameter['pb1'], default_parameter['pb2'])

main_module({'pa1':0, 'pb1':0})

so that if I change the sub-module, the caller can still remain unchanged.

def main_module(parameter = {}):
    default_paramter = dict(
        pa1 = 1, 
        pa2 = 2,
        pc1 = 5,  # new parameters for sub_module_c
        pc2 = 6,
        pc3 = 7,
    )
    default_parameter.update(parameter)
    sub_module_a(default_parameter['pa1'], default_parameter['pa2'])
    sub_module_c(default_parameter['pc1'], default_parameter['pc2'])

main_module({'pa1':0, 'pb1':0})    # remain unchanged
# the caller doesn't even know
# that the implementation of main_module has changed

A even more fascinating way to support the plugin-style sub-modules is that

def main_module(module_list=[], parameter = {}):
    module_mapping = dict(
        use_module_a = sub_module_a,
        use_module_b = sub_module_b,
        use_module_c = sub_module_c,
    )
    default_paramter = dict(
        pa1 = 1, 
        pa2 = 2,
        pb1 = 3,
        pb2 = 4,
        pc1 = 5,  # new parameters for sub_module_c
        pc2 = 6,
        pc3 = 7,
    )
    default_parameter.update(parameter)
    
    for module in module_list:
        module_mapping[module](default_parameter)
        # but have to let the sub_modules pick 
        # the parameter they need in their implementation

# caller can decide which module it wants to use
main_module(['use_module_a', 'use_module_b'], {'pa1':0, 'pb1':0})

There are definitely many better ways to do it, and that’s why I think I am becoming to love Python – the flexibility.