Home IrisCTF writeup for Meaning of Python 2
Post
Cancel

IrisCTF writeup for Meaning of Python 2

Challenge

python2.py

Solution

With the syntax highlighting, we can see that there is a huge byte literal(begin with b'), meaning that this may be the core content of the program.

To see how the control flow goes, let’s first deal with the part before that:

Noticing there are many hex-encoded strings('\xhh'), we can use print() to reveal them

1
print("""WWXWXWXXXXXWWWWXXWWXXWX,lIIIlIIIllIllIIllIII,LILJIJJIJJILLIIJJLL,S2S2SS2S222S2S2SS2222,wxwwxxwwwxxxxwxxxwxx=(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw(__import__('\x7a\x6c\x69\x62'))),(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw['\x64\x65\x63\x6f\x6d\x70\x72\x65\x73\x73']),(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['\x65\x76\x61\x6c'](globals()['\x63\x6f\x6d\x70\x69\x6c\x65'](globals()['\x73\x74\x72']("\x67\x6c\x6f\x62\x61\x6c\x73\x28\x29\x5b\x27\x5c\x78\x36\x35\x5c\x78\x37\x36\x5c\x78\x36\x31\x5c\x78\x36\x63\x27\x5d(wxxwwxwxwxxxwwxwwwwxw)"),filename='\x6e\x6d\x6e\x6e\x6e\x6d\x6e\x6e\x6e\x6e\x6d\x6e\x6e\x6e\x6e\x6e\x6d\x6e\x6e\x6d\x6e\x6e\x6d\x6e\x6e',mode='\x65\x76\x61\x6c'))),(lambda DDDDDDOOooOoDoDooD,wxxwwxwxwxxxwwxwwwwxw:DDDDDDOOooOoDoDooD(wxxwwxwxwxxxwwxwwwwxw)),(lambda:(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['\x65\x76\x61\x6c'](globals()['\x63\x6f\x6d\x70\x69\x6c\x65'](globals()['\x73\x74\x72']("\x67\x6c\x6f\x62\x61\x6c\x73\x28\x29\x5b\x27\x5c\x78\x36\x35\x5c\x78\x37\x36\x5c\x78\x36\x31\x5c\x78\x36\x63\x27\x5d(wxxwwxwxwxxxwwxwwwwxw)"),filename='\x6e\x6d\x6e\x6e\x6e\x6d\x6e\x6e\x6e\x6e\x6d\x6e\x6e\x6e\x6e\x6e\x6d\x6e\x6e\x6d\x6e\x6e\x6d\x6e\x6e',mode='\x65\x76\x61\x6c')))('\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x62\x75\x69\x6c\x74\x69\x6e\x73\x27\x29\x2e\x65\x78\x65\x63'));wxwwxxwwwxxxxwxxxwxx()(S2S2SS2S222S2S2SS2222(lIIIlIIIllIllIIllIII(WWXWXWXXXXXWWWWXXWWXXWX(LILJIJJIJJILLIIJJLL('\x76\x61\x72\x73')))""")

output:

1
WWXWXWXXXXXWWWWXXWWXXWX,lIIIlIIIllIllIIllIII,LILJIJJIJJILLIIJJLL,S2S2SS2S222S2S2SS2222,wxwwxxwwwxxxxwxxxwxx=(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw(__import__('zlib'))),(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw['decompress']),(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['eval'](globals()['compile'](globals()['str']("globals()['\x65\x76\x61\x6c'](wxxwwxwxwxxxwwxwwwwxw)"),filename='nmnnnmnnnnmnnnnnmnnmnnmnn',mode='eval'))),(lambda DDDDDDOOooOoDoDooD,wxxwwxwxwxxxwwxwwwwxw:DDDDDDOOooOoDoDooD(wxxwwxwxwxxxwwxwwwwxw)),(lambda:(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['eval'](globals()['compile'](globals()['str']("globals()['\x65\x76\x61\x6c'](wxxwwxwxwxxxwwxwwwwxw)"),filename='nmnnnmnnnnmnnnnnmnnmnnmnn',mode='eval')))('__import__('builtins').exec'));wxwwxxwwwxxxxwxxxwxx()(S2S2SS2S222S2S2SS2222(lIIIlIIIllIllIIllIII(WWXWXWXXXXXWWWWXXWWXXWX(LILJIJJIJJILLIIJJLL('vars')))

some part are double-encoded, do it again:

1
print("""WWXWXWXXXXXWWWWXXWWXXWX,lIIIlIIIllIllIIllIII,LILJIJJIJJILLIIJJLL,S2S2SS2S222S2S2SS2222,wxwwxxwwwxxxxwxxxwxx=(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw(__import__('zlib'))),(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw['decompress']),(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['eval'](globals()['compile'](globals()['str']("globals()['\x65\x76\x61\x6c'](wxxwwxwxwxxxwwxwwwwxw)"),filename='nmnnnmnnnnmnnnnnmnnmnnmnn',mode='eval'))),(lambda DDDDDDOOooOoDoDooD,wxxwwxwxwxxxwwxwwwwxw:DDDDDDOOooOoDoDooD(wxxwwxwxwxxxwwxwwwwxw)),(lambda:(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['eval'](globals()['compile'](globals()['str']("globals()['\x65\x76\x61\x6c'](wxxwwxwxwxxxwwxwwwwxw)"),filename='nmnnnmnnnnmnnnnnmnnmnnmnn',mode='eval')))('__import__('builtins').exec'));wxwwxxwwwxxxxwxxxwxx()(S2S2SS2S222S2S2SS2222(lIIIlIIIllIllIIllIII(WWXWXWXXXXXWWWWXXWWXXWX(LILJIJJIJJILLIIJJLL('vars')))""")

We can almost see something from it:

1
WWXWXWXXXXXWWWWXXWWXXWX,lIIIlIIIllIllIIllIII,LILJIJJIJJILLIIJJLL,S2S2SS2S222S2S2SS2222,wxwwxxwwwxxxxwxxxwxx=(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw(__import__('zlib'))),(lambda wxxwwxwxwxxxwwxwwwwxw:wxxwwxwxwxxxwwxwwwwxw['decompress']),(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['eval'](globals()['compile'](globals()['str']("globals()['eval'](wxxwwxwxwxxxwwxwwwwxw)"),filename='nmnnnmnnnnmnnnnnmnnmnnmnn',mode='eval'))),(lambda DDDDDDOOooOoDoDooD,wxxwwxwxwxxxwwxwwwwxw:DDDDDDOOooOoDoDooD(wxxwwxwxwxxxwwxwwwwxw)),(lambda:(lambda wxxwwxwxwxxxwwxwwwwxw:globals()['eval'](globals()['compile'](globals()['str']("globals()['eval'](wxxwwxwxwxxxwwxwwwwxw)"),filename='nmnnnmnnnnmnnnnnmnnmnnmnn',mode='eval')))('__import__('builtins').exec'));wxwwxxwwwxxxxwxxxwxx()(S2S2SS2S222S2S2SS2222(lIIIlIIIllIllIIllIII(WWXWXWXXXXXWWWWXXWWXXWX(LILJIJJIJJILLIIJJLL('vars')))

In fact, the keywords are “zlib” and “decompress”. So we decompress the code start with b’x\x9c’ by zlib and get the output.py:

1
2
3
4
5
6
7
8
ocals()['ijjjjjiljlijijllijliill']=globals
ijjjjjiljlijijllijliill()['IlIlIlIlIIlIlIIIIlIIlII'[::+-+-(-(+1))]]=dir
ijjjjjiljlijijllijliill()['IIlIIlllllIIIIIlIllIl'[::+-+-(-(+1))]]=getattr
ijjjjjiljlijijllijliill()['MNNNNMMMNNNNNNNMNN']=locals
MNNNNMMMNNNNNNNMNN()['SSSS22S2S22S222222']=__import__
ijjjjjiljlijijllijliill()['O00OoO00o0oooOO0ooOoOo0']=SSSS22S2S22S222222('builtins').vars
ijjjjjiljlijijllijliill()['llIIlIllIllIlllll']=''.join
......

Highly-obfuscated definitions. Seems difficult to start.

Let’s go down to see what’s below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from builtins import all,dir,exec,print,int,range,open,exit
exec(S2SS2SS2S2S2SSSSS22S222S2)
import sys
import zlib
def nmnmnnnmmmnmnnnnmmmmmnnnn(s,a,b):
    arr=list(s)
    arr[a]=chr(ord(arr[a])^ ord(arr[b]))
    return LLLIIILJJLLLJIILI.join(arr)
def nmnmnnnmmmnmnnnnmmnmmnnnn(s,a,b):
    arr=list(s)
    tmp=arr[a]
    arr[a]=arr[b]
    arr[b]=tmp
    tmp=globals()[LLIJILIIILJLJIJJIJL]
    globals()[jjliiiijljljiiiljjjililjj]=globals()[OOoODODDooDDDODOoOOD]
    globals()[WXWWXWXXWXWXXXXWXWWXWWXW]=tmp
    return iiiljljjijlljjjllli.join(arr)
def xxxwwxxwwwwwwwxxxw(s,a,b):
    arr=bytearray(s)
    arr[b]^=arr[a]
    locals()[IIIIllIllllIllIllIlI]=globals()[IIJLJLJJLJJILLJLL]
    globals()[xxxwxwxwwxxxwxwxw]=globals()[IIIILLIJILJLJLJLILJJL]
    globals()[IIILJJLIILJLILLILLIJLJJII]=locals()[JILLIJILLIJLJLIJIIIIJ]
    return bytes(arr)
def xxwwwxxwwwwwwwxxxw(s,a,b):
    arr=bytearray(s)
    tmp=arr[a]
    arr[a]=arr[b]
    arr[b]=tmp
    return bytes(arr)
def SS2SS2S22S22SSSSSS22S22S2S(flag):
    locals()[S2SSSSSS2SSSSSS2S222S2SS]=IIIllIIIIIlIIIlIllIll
    while mmmnnnnmmnnnmmnmmmmnmnmn:
        if locals()[wxxxxwxwwxxxxxwxxwxxwwxx]==wwxxwwxwxwwxxwwwxxx:
            locals()[IJLJIJJJILLIJILJI]=xxwwwxxwwwwwwwxxxw(locals()[XWWXXWWXXXWWWWXWXXWWWWXW],lijjljjljijiiillijili,SSS22222SSSS222SS222)
            locals()[nmmnmmnnnmmnmnmnnmnnnnm]=xwwxwxxwwwxwwwwxwx
        elif locals()[wwxwwwxwwxwxxwxxxwxxwx]==NNNNMNMNMMNNNMNMMNN:
            locals()[xwxxxwxxxwwxwwwwxxwxxxwww]=xxwwwxxwwwwwwwxxxw(locals()[WXXXWXXWWWWWWWWXXWXWWWWW],nmnmmnnnnnmnmmmmnnmmmmmn,llillliljiijjlijijjiij)
            locals()[LJLIIIJIJJILLJILILI]=XXXXWXXWXXXXXXXWXWXXWXWW
        ...... # omitting similar paragraphs
        elif locals()[WXXXWXWWWXWXXXXWWWXW]==ijlljiiijjjliijli:
            return
def SS2SS2S22S22SSSSSS2SS22S2S(flag):
    locals()[mmmnmnmmmnmmmmmmmmnnm]=xwxwxxxwwxwwwxxxxwxxxx
    while MNNMMNNMNMMMNNMMN:
        if locals()[mnmmnnmmmmnmmmmmnmnnm]==wwxxxwwxxxxwxxwwxxx:
            locals()[IIILILIIJJIILIIJJL]=nmnmnnnmmmnmnnnnmmmmmnnnn(locals()[Oo00oo0Oo0O00o0o00OoOOo],xwwwxwwwxwxxxxxwwwwwwxxxx,JIJJJJJLIIIJILJIJLLII)
            locals()[WWWXXWWWXWWWXXXWWWXXXW]=ijjjjlilijjiijlij
        elif locals()[MNMMMNNNNNMMMMNNMNNMM]==OODoOODDooDDDOOOODDOOD:
            locals()[OOoOoOo00oooOO0ooOo0o]=nmnmnnnmmmnmnnnnmmnmmnnnn(locals()[OOooOOo0oO0oo0Oo000o0o0],WXWXXXWWWXWWWXXWWXXW,IllIllllllIllIIIIIlI)
            locals()[S2S22S22SSSSSS2SS2SS]=lIlllllIIllIIlIlllIl
        ...... # omitting similar paragraphs
        elif locals()[IIllIllIIIIlIIIIIllI]==mmmnnmmmmmnmmnnnmmmnmnm:
            return
def main():
    if len(sys.argv)<=LIJIIILJLJJILIILLILJL:
        print(S22222S22S2SSS2S22SS2S22S2)
        exit(Oo00ooO0OOO00Oo0O0)
    locals()[SSS22SS222S222SSS2S]=sys.argv[DoOoODOoooDOoODoD]
    locals()[oDDDoOOoooOOoooOoODDO]=len(locals()[wxxwxwxxxxxwwxxxwxwxwxww])
    if locals()[S2222SSS2SSS22222S]<IIlIllIIlIlIIIlIIl:
        print(ODOOOoDDDDOOoooDo)
        exit(IIILLJIIIJIIJJLIJIJLJLILI)
    SS2SS2S22S22SSSSSS2SS22S2S(locals()[lljlililiiljliiij])
    locals()[S2S2SS222S22S222S22SSSS]=zlib.compress(locals()[mnmmmnnmnmnnmnnmmmmmmm].encode(O00Oo0OO00OOOOoo00OooOo0O))
    locals()[LJLJJLJIJIIJILLJJ]=len(locals()[OoO0O000000ooo0oOo0ooOO0O0])
    if locals()[xwwxxxwxxxxwwxwwxww]<wwxwxwxxwxwxxwxxwwwwx:
        print(WWWXXWXWXWWXWXWWXWXXWX)
        exit(ljijlljjiiiljjljjjiji)
    SS2SS2S22S22SSSSSS22S22S2S(locals()[SS2SS2SS22S222SSSS22SSS2])
    if locals()[SSSS222S22SS2222SS2S2S]==OO0oOO00oOo0O000oo0OOO0:
        print(XXWWWWXXWWWWWXWXW)
    else:
        print(nmnmnmnnnnmnnmnmnmmnnm)
main()

We see something familiar. From Meaning of Python 1, we know these two functions do not really change the flag, so we only have to find the cipher and decode it with zlib.

So where’s the cipher? Do we really have to look over all the highly-obfuscated definitions?

No. Since all of them are just definitions, just run them in an interactive terminal and use vars() to see their runtime values.

With a little knowledge of zlib format, we search for string begin with b'x\x9c':

1
2
3
4
>>>[print(i) for i in vars()]
......
('OO0oOO00oOo0O000oo0OOO0', b'x\x9c\xcb,\xca,N.I\xab\xce\xa8,H-\xca\xcc\xcf\x8b7,\x8e\xcf3(\x89O\x8c/3.\xaa\x8cO70H\x897HJ+5M6)1(R\xac\x05\x00\xce\xff\x11\xdb')
......

decompress it with zlib again, and we get the flag:

1
irisctf{hyperion_1s_n0t_a_v3ry_g00d_0bfu5c4t0r!}
This post is licensed under CC BY 4.0 by the author.

-

LA CTF 2023 Writeup

Trending Tags