Square CTF 2019 Writeup's
[*]-challenges
[+] (one - 100 pts) Talk to me
[+] (two - 700 pts) Aesni
[+] (three - 150 pts) Decode me
[+] (five - 200 pts) Inwasmble
[+] (seven - 600 pts) Lockbox
[+] (nine - 700 pts) Sudo make me a flag
Our Team Invaders ended up at 19th position
With points 3450 points
Talk to me
A service running at `talk-to-me-dd00922915bfc3f1.squarectf.com:5678`$ nc talk-to-me-dd00922915bfc3f1.squarectf.com 5678 Hello! aaaaaaaaaaaa Sorry, I can't understand you.Saying Hello! and asking for input(aaaaaaaaaaaa) Then returning a message
After some trails, Two errors meant a lot (for 1 and ')
$ nc talk-to-me-dd00922915bfc3f1.squarectf.com 5678 Hello! 1 undefined method `match' for 1:Integer /talk_to_me.rb:16:in `receive_data' /var/lib/gems/2.5.0/gems/eventmachine-1.2.7/lib/eventmachine.rb:195:in `run_machine' /var/lib/gems/2.5.0/gems/eventmachine-1.2.7/lib/eventmachine.rb:195:in `run' /talk_to_me.rb:31:in `'
$ nc talk-to-me-dd00922915bfc3f1.squarectf.com 5678 Hello! ' (eval):1: unterminated string meets end of file /talk_to_me.rb:16:in `eval' /talk_to_me.rb:16:in `receive_data' /var/lib/gems/2.5.0/gems/eventmachine-1.2.7/lib/eventmachine.rb:195:in `run_machine' /var/lib/gems/2.5.0/gems/eventmachine-1.2.7/lib/eventmachine.rb:195:in `run' /talk_to_me.rb:31:in `Our Input in passing into eval function with some method call (match) may be like eval("%s.match('xxxx')"%input)'
But When passing a or any string it is not returing error , Just saying (Sorry, I can't understand you.) means our input is not passed into eval(blacklist check)
After brute forcing for chars we can use for input the result is 0123456789\"%'()*+,-./:;<=>{|}, then tried '1' a valid string with whitelist chars
$ nc talk-to-me-dd00922915bfc3f1.squarectf.com 5678 Hello! '1' I wish you would greet me the way I greeted you.I wish you would greet me the way I greeted you. means Hello!, matching our input with 'Hello!'; eval("%s.match('Hello!')")
Goal is to create a string using 0123456789"%'()*+,-./:;<=>{|};
A way is ('' << 97) which gives "a" ord('a') is 97
"Hello!" => ('' << 72)+('' << 101)+('' << 108)+('' << 108)+('' << 111)+('' << 33)
$ nc talk-to-me-dd00922915bfc3f1.squarectf.com 5678 Hello! ('' << 72)+('' << 101)+('' << 108)+('' << 108)+('' << 111)+('' << 33) It's so great to talk to you! Maybe you know what to do with this flag-2b8f1139b0726726?
Aesni
Given a binary file names aesni$ ./aesni ⛔ $ file aesni aesni: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, strippedA stripped binary , there are no functions, just one assebmbly code at 0x804817c
pwndbg> disass 0x804817c,0x80481a0 Dump of assembler code from 0x804817c to 0x80481a0: 0x0804817c: mov edi,esi 0x0804817e: mov DWORD PTR ds:0x80481a1,ecx 0x08048184: movups xmm0,XMMWORD PTR ds:0x80481a1 0x0804818b: aesenc xmm0,xmm1 0x08048190: movups xmm2,XMMWORD PTR [esi] 0x08048193: pxor xmm2,xmm0 0x08048197: movups XMMWORD PTR [esi],xmm2 0x0804819a: add esi,0x10 0x0804819d: loopne 0x804817e 0x0804819f: jmp ediFunctionality is simply , aes decrypting the text in esi using key in xmm1 and No of rounds to perform in ecx And jumping to that decrypted assembly code(need dynamic analysis)
The entry point is 0x8048060
► 0x8048060 movups xmm1, xmmword ptr [0x8048077] 0x8048067 lea esi, [0x80481f1] 0x804806d mov ecx, 6 0x8048072 jmp 0x804817cEncrypted Assembly code is at 0x80481f1 , with key at 0x8048077 # "flap-d0d8411ec06" and rounds '6'; After Dectyption
pwndbg> disass 0x80481f1,0x8048230 Dump of assembler code from 0x80481f1 to 0x8048230: => 0x080481f1: pop eax 0x080481f2: cmp eax,0x2 0x080481f5: je 0x8048211 0x080481f7: movups xmm1,XMMWORD PTR ds:0x8048231 0x080481fe: lea esi,ds:0x8048251 0x08048204: mov ecx,0x4 0x08048209: add eax,0x2 0x0804820c: jmp 0x804817c 0x08048211: movups xmm1,XMMWORD PTR ds:0x8048251 0x08048218: mov esi,eax 0x0804821a: movups xmm1,XMMWORD PTR ds:0x8048241 0x08048221: lea esi,ds:0x8048291 0x08048227: mov ecx,0x3 0x0804822c: jmp 0x804817cIf no of arguments are 2 then jumping to 0x8048291 , or else 0x8048251 (Which prints '-' symbol);
After Decryption of 0x8048241
0x8048291 pop eax 0x8048292 inc eax 0x8048293 movups xmm2, xmmword ptr [0x80482c1] 0x804829a movups xmm1, xmmword ptr [0x80482b1] 0x80482a1 lea esi, [0x804809c] # Then To 0x804809c 0x80482a7 mov ecx, 8 0x80482ac jmp 0x804817c
pwndbg> disass 0x804809c,0x80480ef Dump of assembler code from 0x804809c to 0x80480ef: => 0x0804809c: lea esi,ds:0x80480ef 0x080480a2: mov edi,esi 0x080480a4: mov ecx,0xd 0x080480a9: cld 0x080480aa: lods al,BYTE PTR ds:[esi] 0x080480ab: xor al,0x55 0x080480ad: stos BYTE PTR es:[edi],al 0x080480ae: loop 0x80480aa 0x080480b0: pop edi 0x080480b1: lea esi,ds:0x80480ef 0x080480b7: mov ecx,0xd 0x080480bc: repz cmps BYTE PTR ds:[esi],BYTE PTR es:[edi] 0x080480be: jne 0x80480d7 0x080480c0: movups xmm1,XMMWORD PTR ds:0x804810c 0x080480c7: lea esi,ds:0x804811c 0x080480cd: mov ecx,0x5 0x080480d2: jmp 0x804817c 0x080480d7: movups xmm1,XMMWORD PTR ds:0x80480fc 0x080480de: lea esi,ds:0x8048251 0x080480e4: mov ecx,0x4 0x080480e9: jmp 0x804817c 0x080480ee: retSimply XORing ds:0x80480ef with 0x55 and then comparig with 2nd argument;
If equal printing flag , or else 0x8048251 (Which prints '-' symbol)
$ python xxx.py ThIs-iS-fInE\x006b6 $ ./aesni ThIs-iS-fInE flag-cdce7e89a7607239
Decode me
Given encoder.pyc and decodeme.png.enc files ; decodeme.png.enc is encoded with encoder.pyc,we need to decode the decodeme.png.enc by reversing the algo implemented in encoder.pyc
Decompiled the encoder.pyc to python code using uncompyle6
A simple Reverse on the code
decodeme.png
Inwasmble
Given a website at https://2019.squarectf.com/static/files/7a32fbe18afbbd9f_inwasmble.html ;onKeyUp="go()" ; There is no such function only one script
As specified in chall name , all are Invisible (Inwasmble) chars
script -> unescape -> escape -> '' <- br="">Everything is in that string only
Implemented web Assembly; In which there is a fuction validate `wa.exports.validate()`, Which is validating our input!
Dissembled Web Assembly
By Analysing the functionality in Assembly ,
Key is constant , So a Simply reverse >>
The input key is "Impossible is for the unwilling."
Lockbox
A Lockbox box running at https://lockbox-6ebc413cec10999c.squarectf.com/Given it's source code lockbox.go
The Service is Encrypting the Data and storing in database,And calculating the hmac for that data and returing it to user after succesful upload.And also user can lock that upto a period of time , by specifying when it has to open.
Given A Image file
After checking the source code of server (lockbox.go)
found an boolean sql injection `panicIfError(env.db.First(&text, r.URL.Query().Get("id")).Error)` in id parameter(GET /id=??&hash=xxxx)
Exploiting the Injection to leak the Data at ID=3
But the data is stotred as Encrypted ,We need to decrypt it, but there is functionality useful for us: (captcha GET /captcha?c=xxxx&w=00)
To make the user to dont know the captcha value , Encrypted value is sent to user(source code); From there a request goes to /captcha with that encrypted value , decrypts on server side and create's a captcha with that decrypted value and return's it,
So we can decrypt our flag with captcha
The captcha is
Sudo make me a flag
Given a make fileThere are total 26 functions, Important functions that we need are
Our input must be like (******-********) two words seperated by -, l= n(first word) q= n(second word) n=filters x and y only from input def n(S): # Parse input to record x,y values first = ''.join([x for x in S.replace('x','x ').split() if x=='x']) second = ''.join([x for x in S.replace('y','y ').split() if x=='y']) return first + second # Due to it's filtering functionallity ( xxxyy becomes xxxy ) & (xxxyyy becomes xxxyy) & (yyxx becomes yyx) k= (S1,S2): # Concat S1, S2 with S2'x as S1'x and S2'y as S1'y #Ex (xxy,xyy => xxxyyy) b= (S1,S2): # Concat S1, S2 with S2'y as S1'x and S2'x as S1'y #Ex (xxy,xyy => xxxxyy) def P(S1, S2): if 'x' in S1: s1 = p(o(u(S1)), S2) return k(S2,s1) elif 'y' in S1: s1 = p(o(i(S1)), S2) return b(S2,s1) else: return '' # main function to focus on, Repeats the String S2 based on difference between number of x's and y's # If S1.count('x') > S1.count('y'): repeats the S2 normally using k function diff = S1.count('x') - S1.count('y') returns 'x'*(diff * S2.count('x'))+'y'*(diff * S2.count('y')) # else: repeats the S2 inverted every time by b function; For one iteration count('x') increases , for next iteration 'y' , .... # The diffecrence between count('x') and count('y') remainds constant for whatever diff o=which removes the eqaul number of 'x' and 'y'; returns '' when count('x') == count('y') flag = $(if $(or $(call o,$(d)), $(call o,$(x)) ), @echo nope, $(if $(call o, $(call b, $(l), $(q) ) ), $(s), @echo nope ) ) Two checks for flag First : No of 'x' and 'y' must be equal for $(d)=r(first part) , $(x)=r(second part) Second : count('x')-count('y') must be differ for $(d) and $(x)Goal: find the two strings(differ in count('x')-count('y')) which makes the r() function to return string with count('x') == count('y')
Note: count('x') > count('y') for input ; because then only we can increase the diff between x&y for output
Focussing of r function; A Simple math
Let: S be our input A = S.count('x') ; B = S.count('x') r(S) = > b(a(S),y(S)) ------------------------------------------------------------------------------ a(S) => k(m(S) , h()) m(S) => p(S,S) m(S) : A*(A-B) x's && B*(A-B) y's h() : 784 x's && 2 y's # Always same , it returns a constant a(S) : k(m(S),h()) ; Concatnating with k function ax = A*(A-B) + 784 = A^2 - AB + 784 # No of x's returned by a(S) ay = B*(A-B) + 2 = AB - B^2 + 2 # No of y's returned by a(S) ------------------------------------------------------------------------------ y(S) = p(S, t()) t() : 59 x's && 2 y's # Always same , it returns a constant yx = (A-B)*59 = 59A - 59B # No of x's returned by y(S) yy = (A-B)*2 = 2A - 2B # No of y's returned by y(S) ------------------------------------------------------------------------------ r(S) = > b(a(S),y(S)) # As a(S) , y(S) are Concatinating with b function ; It inverts the Second params x,y count rx = ax + yy = A^2 - AB + 784 + 2A - 2B # No of x's returned by r(S) ry = ay + yx = AB - B^2 + 2 + 59A - 59B # No of y's returned by r(S) ------------------------------------------------------------------------------ Our first condintion is to string returned by r(S) function must satisfy count('x') == count('y') rx == ry A^2 - AB + 784 + 2A - 2B = AB - B^2 + 2 + 59A - 59B A^2 - 2AB + B^2 = 57A - 57B -782 (A-B)^2 = 57(A-B) - 782 ------------------------------------------------------------------------------ Our Second condition is to find two strings which are differ in `count('x') - count('y')` Let Q = A-B # count('x') - count('y') (A-B)^2 = 57(A-B) - 782 Q^2 = 57^Q -782 Q^2 - 57^Q + 782 = 0 A Quadratic quation ; Two roots = two difference `count('x') - count('y')` values The Values are Q = 23 ; Q = 34The Input string is ( 'x'*23+ '-' + 'x'*34 ) or ('x'*24+'y'*'2'-'x'*34) or ... ... .. infinite solutions with difference `count('x') == count('y')` => 23, 34
Here difference between x & y matters not the count of 'x' and count of 'y'
Note : Due to n function filter functionality xxyy becomes xxy
Finally
$ make `python -c 'print "x"*23 + "-" + "x"*34'` && cat flag.out flag-04cc001141d91337867996669dfcee39 - $
Comments
Post a Comment