First, I have to admit that I have not captured this flag!  But ... since I have just seen the other write-up and figured that I could retrieve the very same admin_k I thought it's worth writing this down  ... it follows a little different no-crypto approach ;)
program setups rsa and elgamal keys to be used for encryption/decryption of a message and for signing.
Later it turns out that we can completly ignore the signing part ...
program runs 200 seconds until we hit SIGALRM ... this often means we might have to script the exploit, since manual in/output might take too long ... but let's just see
user can register or login#### register:if name == admin need to provide admin_k (which was read from file)if the key is correct we get the flag!
-> goal get admin key!
for other users:
you enter a name (there will be a length check...)  then the rsa encrypted string will be:  msg = name + b'\x00' + admin_k  length check is on msg (means name + admin key + 1 null byte)  the check makes sure that size (aka number of bits of msg) does not exceed 700  
from there we can get the size/len of the admin key by entering some names  and see when we get the 'Too long username' message  here it was a string with length (bytes) of 41 that passed, 42 will already be larger than 700 BITS  41 + 1 + admin = 700 -> 700 - 42*8 = 364 -> 364/8=45R4 admin key should have length 45  
username\00admin_key  N    1  45  
but again the msg is extended with data before encryption.  this time like this:  msg = msg + urandom(120 - len(msg))  
it's easy to see that if length of message would equal 120 there would not be any random part  120 = len(name + b'\x00' + admin_k)  120 - 1 - 45 = 74 -> so choose name with N=74 bytes  
mmmh 74 * 8 = 512 bits ... we had admin_k with 45 * 8 = 360 bits -> 512+360 > 700 !! bad :(  
if we look further at the code, the other choice besides register is to login  to login you need a ticket which is the encrypted msg which was returned after registering  and the signature parts. if you enter false signature it does not matter only a warning is printed but program contines
from the code:
```msg = cry.decrypt(ticket)  msg = long_to_bytes(msg)  name = msg.split(b'\x00')[0]  print('Welcome!{}'.format(name))  ```
so after decrypt message is split again at the null byte and the name is returned  if we would have a message where admin_k does not contain random bytes and the name would be null as well  I guess after split() we would be greeted with the admin key that could be used to register with 'admin'  
I tried this python code to see if I can generate suitable name string (still need to hope that input() would accept it)```admin = 'foobar'  name = b'\x00'*1print('len:  '+str(len(name + b'\x00' + admin)))print('size: '+str(size(bytes_to_long(name + b'\x00' + admin))))
name = b'\x00'*74print('len:  '+str(len(name + b'\x00' + admin)))print('size: '+str(size(bytes_to_long(name + b'\x00' + admin))))gives us:len:  8size: 47len:  81size: 47```interesting ... we can have a 74 byte null (name) string with length 74, but size(bytes_to_long(name)) will be zero
so this would be the time to put everything into a script and see if it works  but time run out and only a few manual tries were done but it seems it worked
So here are my (manual) steps ```>>> nc=remote('47.75.53.178',9999)>>> print(nc.recv())b'welcome to Fantasy Terram\n65537\n140629472245999285098064316303866659629185812774218573790665303954294872600262448905882579177430447502384476296889455526009245187787784270910730776435647281906172951059742370845233593495596605880717057027739444519332751527512894864042942924679461080488348066457317250117451797086450925496865588827148175066791\n331594477686558113580787539285291719147\n144138144825272306357576043429581630357\n58183684653320143077677950713948783289\nPlease [r]egister or [l]ogin :>>'>>> nc.send("r\n")>>> print(nc.recv())b'please input your username:>>'>>> nc.send(b'\x00'*74)>>> nc.send("\n")>>> ans=nc.recv()>>> print(ans)### note we need to grep first line from ans -> our login ticket b'**1150307703645571841691124872395986074445001716352354369904193119148817280160469269859716991052866383451320166269287258385015274222555291986480385108167877033070349751370633422865847917612573602863230184749721945543492207722907777189700351702934150482163081676826889438295076608552683903022157946512008773972**\n129390639790651743848770239302728311235\n109164253264931500125431647817682215432\nPlease [r]egister or [l]ogin :>>'>>> nc.send("l\n")>>> nc.sendline("1150307703645571841691124872395986074445001716352354369904193119148817280160469269859716991052866383451320166269287258385015274222555291986480385108167877033070349751370633422865847917612573602863230184749721945543492207722907777189700351702934150482163081676826889438295076608552683903022157946512008773972")>>> print(nc.recv())b'ticket:>>sig[0]'>>> nc.sendline("123")>>> nc.sendline("123")>>> print(nc.recv())b'sig[1]Wrong signature!\nWelcome!b'1qsxcvghyu89olkmnbvd2#$%^&*()_OKMNBFRT:"><~&*r'\nPlease [r]egister or [l]ogin :>>'
>>> nc.send("r\n")>>> print(nc.recv())b'please input your username:>>'>>> nc.send("admin\n")>>> print(nc.recv())b"please impurt admin's key:>>">>> nc.sendline("1qsxcvghyu89olkmnbvd2#$%^&*()_OKMNBFRT:"><~&*r")>>> print(nc.recv())b'Liar! Get out of here!\n'```
So what went wrong?  two things I guess ...  a) the string I send back is one char too long, remember we figured it should be 45 bytes the last r can be skipped and  b) the double quote shall be escaped when sending so it should have looked like:  ``>>> nc.sendline("1qsxcvghyu89olkmnbvd2#$%^&*()_OKMNBFRT:\"><~&*")``
