The author provided the challenge source code, we have to send getflag followed by its signature which will be verified in if privkey.verify(b'getflag', (signature,)):.
This is a classic RSA blinding attack, the full details about the attack are available at http://the2702.com/2015/09/07/RSA-Blinding-Attack.html. I made a python script based on the pwn lib to interact with the service.
importreimportcodecsimportrandomfromCrypto.PublicKeyimportRSAfrombinasciiimportunhexlify,hexlifyfrompwnimport*srv=remote('rsamachine.wpictf.xyz',31337)pubkey=srv.recv().strip()key=RSA.importKey(pubkey)print("[!] Got public key")M=int(hexlify("getflag"),16)N=key.ne=key.er=3# random.randint(2, N-1)mbis=(M*pow(r,e))%Nmessagebis=("%2X"%mbis).decode('hex')srv.send("sign "+messagebis+"\n")sbis=srv.recv()sbis=long(sbis.strip())#sbis = pow(mbis, d) % N print("[!] Got S' : {}".format(sbis))s=(sbis/r)%Nsrv.send("getflag {}\n".format(s))print(srv.recv())
We got the flag after launching the script 3 times.
╰─$ python2 rsablind.py
[+] Opening connection to rsamachine.wpictf.xyz on port 31337: Done
[!] Got public key
[!] Got S' : 8055189041943281850539614428987268833243977988231476308451969394241131492275713532521566856414705140678584275459454061478877916901106021929082261596304029000380356771010090392077825985126904892021860846170710444878788617553685554227251040415596010342529263252780579779283805197748539892098561765320527416126709326474068550668984482014647358415646453014451009099645828063210244579362249356356992100432879012681260104886379237896331092235634504293978157618536973885986939804073798159721968127183030650941348417673375708632952880399373025493539732962654422773982210391960030492635331940490213507770535612609263131485740
WPI{m411e4b1e_cipher5_4re_d4ngerou5}
[*] Closed connection to rsamachine.wpictf.xyz port 31337
description: A tribute to the former God Emperor of CSC and Mankind, Ultimate Protector of the CS Department, and Executor of Lord Craig Shue’s Divine will.
category: Miscellaneous - 150
You want some game play ?
Yeah I know I’m pretty good but not enough to win the game tho.
As you can see, it looks like the boss has infinity health (that’s not true, it’s a huge number…).
Okay, let’s launch Cheat Engine.exe
What are we looking for ? anything displayed on the screen that can make me win:
- `HP` ? I can put it to 200 and never lose life but that won't make me kill the boss faster.
- `Death` ? Hum I can identify the `die` function, so i won't die or maybe i can force the boss to die ?
- `level` ? Why not try to find the level in memory and change it to the level after the boss (boss should be level 6 if the level on the image is truly 1).
Modifying the level seems interesting. This is how I find the correct value:
So the level is stored at 0x6ff82c.
Let’s see what is accessing this value: right click -> Find out what accesses the address then finish the level to see what code is writing the next level:
The instruction is at 0xb50201.
cmon do it IDA (in debug mode of course):
.text:00B501E5 loc_B501E5:
.text:00B501E5 call sub_B717B0
.text:00B501EA mov edx, dword_C13BE4
.text:00B501F0 movzx ecx, di
.text:00B501F3 shl ecx, 10h
.text:00B501F6 movzx eax, si
.text:00B501F9 or ecx, eax
.text:00B501FB mov eax, [edx+1F0h]
.text:00B50201 mov [ebp-4], eax
.text:00B50204 mov eax, [edx+0D8h]
.text:00B5020A mov [ebp-8], ecx
.text:00B5020D test eax, eax
.text:00B5020F jz short loc_B5024E
The level is stored in [edx+1F0h]. all we have to do is to set this value to 7 (one more gif =) ):
Well, that was fast ! I recorded it with vlc, so I can go frame by frame:
The flag is WPI{j0in_th3_illumin@ti_w1th_m3}
PS1: I’m good @ gaming right ? You can find me on Twitch here =)
PS2: Best WPI challenge in my opinion, well done to the author ;)
description: Decrypt PIY{zsxh-sqrvufwh-nfgl} to get the flag!
category: Crypto - 100
The code was provided as a .pyc file (available at https://ctf.wpictf.xyz/files/d9543469d876cffa70bb84667ed5d369/jocipher.pyc).
It’s a compiled python file which means we can get the code back with uncompyle.
# uncompyle6 version 3.2.6# Python bytecode 2.7 (62211)# Decompiled from: Python 3.7.3 (default, Mar 26 2019, 21:43:19) # [GCC 8.2.1 20181127]# Embedded file name: ./jocipher.py# Compiled at: 2019-03-01 18:41:21importargparse,renum=''first=''second=''third=''defsetup():globalfirstglobalnumglobalsecondglobalthirdnum+='1'num+='2'num+='3'num+='4'num+='5'num+='6'num+='7'num+='8'num+='9'num+='0'first+='q'first+='w'first+='e'first+='r'first+='t'first+='y'first+='u'first+='i'first+='o'first+='p'second+='a'second+='s'second+='d'second+='f'second+='g'second+='h'second+='j'second+='k'second+='l'third+='z'third+='x'third+='c'third+='v'third+='b'third+='n'third+='m'defencode(string,shift):result=''foriinrange(len(string)):char=string.lower()[i]ifcharinnum:new_char=num[(num.index(char)+shift)%len(num)]result+=new_charelifcharinfirst:new_char=first[(first.index(char)+shift)%len(first)]ifstring[i].isupper():result+=new_char.upper()else:result+=new_charelifcharinsecond:new_char=second[(second.index(char)+shift)%len(second)]ifstring[i].isupper():result+=new_char.upper()else:result+=new_charelifcharinthird:new_char=third[(third.index(char)+shift)%len(third)]ifstring[i].isupper():result+=new_char.upper()else:result+=new_charelse:result+=charprintresultreturn0defdecode(string,shift):result=''shift=-1*shiftforiinrange(len(string)):char=string.lower()[i]ifcharinnum:new_char=num[(num.index(char)+shift)%len(num)]result+=new_charelifcharinfirst:new_char=first[(first.index(char)+shift)%len(first)]ifstring[i].isupper():result+=new_char.upper()else:result+=new_charelifcharinsecond:new_char=second[(second.index(char)+shift)%len(second)]ifstring[i].isupper():result+=new_char.upper()else:result+=new_charelifcharinthird:new_char=third[(third.index(char)+shift)%len(third)]ifstring[i].isupper():result+=new_char.upper()else:result+=new_charelse:result+=charprintresultreturn0defmain():parser=argparse.ArgumentParser()parser.add_argument('--string','-s',type=str,required=True,help='the string to encode or decode')parser.add_argument('--shift','-t',type=int,required=True,help='the shift value to use')parser.add_argument('--encode','-e',required=False,action='store_true',help='encode the string')parser.add_argument('--decode','-d',required=False,action='store_true',help='decode the string')args=parser.parse_args()setup()p=re.compile('[a-zA-Z0-9\\-{}]')ifp.match(args.string)isnotNone:ifargs.encode:ret=encode(args.string,args.shift)else:ifargs.decode:ret=decode(args.string,args.shift)ifretisnot0:print'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]'else:print'Sorry, this cipher only uses the [a-zA-Z0-9\\-{}]'returnif__name__=='__main__':main()# okay decompiling jocipher.pyc
The challenge’s author left a decode function, and a command line helper.
We can use the python jocipher.py --decode STRING_TO_DECODE and try to bruteforce the shift, unfortunately there were multiple flags starting by WPI
description: Come on down and get your flag, all you have to do is enter the correct password …
category: Web - 150
Trying some input:
It seems that we have to guess the password, or maybe…?
$ echo-n"SGV5IEdvdXRoYW0sIGRvbid0IGZvcmdldCB0byBibG9jayAvYXV0aC5waHAgYWZ0ZXIgeW91IHVwbG9hZCB0aGlzIGNoYWxsZW5nZSA7KQ==" | base64 -d
Hey Goutham, don't forget to block /auth.php after you upload this challenge ;)
The auth.php file:
Hum -> extract($_GET)
That means we can rewrite previous variable declarations !
Considering the script is using get_contents, we can suppose that changing the $passcode will make get_contents return an empty string.