m0h1th
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # HSCTF-10 Writeup ## rev/1125899906842622 - 492 points ### Description: I found this credit card on the floor! ### Challenge files: * `1125899906842622.py` --- ### Initial Analysis ```python! a = int(input()) t = a b = 1 c = 21140326319332556493517... verified = False while 1: if b == 4: verified = True break d = 2 + (1125899906842622 if a&2 else 0) if a&1: b //= d else: b *= d b += (b&c)*(1125899906842622) a //= 4 if verified: t %= (2**300) t ^= 1565959740202953... print(t) ``` We have a few interesting numbers that we notice first, `c` which is a 2500 bit number, `1125899906842622 = 2**50 - 2`, which happens to be the name of the challenge. And then there's number that `t` is finally XORed with, which I'm assuming will give us the flag. Going through the flow of the program, we see that `t` and `a` are in our control. And seemingly, the goal is to set `verified` to `True`, i.e., to set `b` to 4. Trying random inputs makes the program run indefinitely. Trying to print out the values of `b` at each iteration, the value seemingly grows, which is not what we want. Let's take a closer look at what's happening: In each iteration, the lower 2 bits of `a` play a role in deciding the values of `d` and `b`. Which means, `d` can either be `2**50` or `2` and `b` can either be divided by or multiplied by that value. ## Functioning A multiplication or division with a power of 2 is essentially a left shift or right shift respectively. So in each iteration, the lower two bits of a control a left or right shift by 1 or 50. | a&2 | a&1 | d | Function | |-----|-----|-------|----------| | 0 | 0 | 2 | b<<1 | | 0 | 1 | 2 | b>>1 | | 1 | 0 |2\*\*50| b>>50 | | 1 | 1 |2\*\*50| b<<50 | And since `a` is our input, we can control the value of `b` using a series of these operations. We start at `b=1` and we need to end at `b=4`. However, we have this line that comes after each operation. `b += (b&c)*(1125899906842622)` This is the reason that `b` grows almost every time we run it with random inputs. Considering the fact that we start with b as just 1 bit, and the desired output is also just 1 bit --> `100` (4) ## How I made a game out of this ( •_•)>⌐■-■ (⌐■_■) Having no idea of how to find the right number to input, I thought of this approach: 1. Shift a bit across `c`, starting from bit position 0 and end up at bit position 2 2. Think of the set bits (1) of `c` as mines. Avoid them at all costs! I couldn't think of an algorithm to do this yet, so I thought I'd make a simple game out of it to interact with it. The first version of it printed the binary of `c` linearly, and placed a red bit that you could move around using 4 inputs: `l1`, `r1`, `l5`, `r5` Using this control system got tiring really quick, so I decided to improve the game. I bound the left and right arrow keys to 1 bit shifts, and up and down arrows to 50 bit shifts. The player's current position would be highlighted in red. I also made it so that it would record the moves that you made, and remove redundant moves. I played this for more time than I'm willing to admit, before I realized that it was just a 50x50 grid. So I changed the game accordingly to print the binary as a 50x50 grid instead one line. The up and down moves would actually be moving me up and down the grid (obviously). ![](https://hackmd.io/_uploads/r1q3jEDP2.gif) So all I had to do was solve this maze using some algorithm, and I started looking for one. (Part of me still wanted to solve it using the game...) ## Solution I figured out that I could use a Breadth-First search algorithm on this to find a path from the start to the finish. The algorithm works by traversing the maze in a breadth-first manner. It keeps track of the current position, and distance. In each iteration, it checks for available paths in all four directions and queues the unexplored paths. When it finally finds the goal point, it returns the path that was taken to reach it. Our starting point would be `(49, 49)`, the initial bit position, and the goal would be at `(49,47)`. I took some code from my game, modified it and used BFS to find a path. Since I was using code from an earlier version of the game, the path would be a list of `l1`s and `r1`s. I took the lazy approach and decided to parse this instead of changing the code itself. I get this big list of moves: ```python! ['l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'l1', 'l1', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'l5', 'l5', 'r1', 'r1', 'r1', 'r1', 'r5', 'r5', 'r1', 'r1', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'l1', 'l1', 'l5', 'l5', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'l5', 'l5', 'l1', 'l1', 'l5', 'l5', 'l1', 'l1', 'r5', 'r5', 'l1', 'l1', 'l5', 'l5', 'l1', 'l1', 'l5', 'l5', 'r1', 'r1', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l5', 'l5', 'l1', 'l1', 'l1', 'l1', 'l5', 'l5', 'r1', 'r1', 'l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'r5', 'r5', 'r1', 'r1', 'r5', 'r5', 'l1', 'l1', 'l1', 'l1', 'l1', 'l1', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'l1', 'l1', 'l1', 'l1', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l5', 'l1', 'l1', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r5', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1', 'r1'] ``` Which I reverse and convert back to binary using the table mentioned earlier. Feeding that number as input to the challenge script gives us an output in no time! ![](https://hackmd.io/_uploads/rJCcCBwPn.gif) `OP: 50937517511040739473747084954399628437899554758014667643591355768086908816264879291316093` Converting this back to bytes gives us the flag! Flag: `flag{l4byr1nth_9abe79d712e6dd52c4597}` ## Solve script: ```python! from collections import deque c = 211403263193325564935177732039311880968900585239198162576891024013795244278301418972476576250867590357558453818398439943850378531849394935408437463406454857158521417008852225672729172355559636113821448436305733721716196982836937454125646725644730318942728101471045037112450682284520951847177283496341601551774254483030077823813188507483073118602703254303097147462068515767717772884466792302813549230305888885204253788392922886375194682180491793001343169832953298914716055094436911057598304954503449174775345984866214515917257380264516918145147739699677733412795896932349404893017733701969358911638491238857741665750286105099248045902976635536517481599121390996091651261500380029994399838070532595869706503571976725974716799639715490513609494565268488194 cb = bin(c)[2:] def find_shortest_path(start, end, grid): rows = len(grid) cols = len(grid[0]) visited = [[False] * cols for _ in range(rows)] distance = {} queue = deque([(start, [])]) distance[start] = 0 while queue: curr, path = queue.popleft() row, col = curr if curr == end: return path # Check left if col > 0 and not visited[row][col-1] and grid[row][col-1] != '1': new_dist = distance[curr] + 1 if (row, col-1) not in distance or new_dist < distance[(row, col-1)]: distance[(row, col-1)] = new_dist queue.append(((row, col-1), path + ['l1'])) visited[row][col-1] = True # Check right if col < cols-1 and not visited[row][col+1] and grid[row][col+1] != '1': new_dist = distance[curr] + 1 if (row, col+1) not in distance or new_dist < distance[(row, col+1)]: distance[(row, col+1)] = new_dist queue.append(((row, col+1), path + ['r1'])) visited[row][col+1] = True # Check up if row > 0 and not visited[row-1][col] and grid[row-1][col] != '1': new_dist = distance[curr] + 1 if (row-1, col) not in distance or new_dist < distance[(row-1, col)]: distance[(row-1, col)] = new_dist queue.append(((row-1, col), path + ['l5'])) visited[row-1][col] = True # Check down if row < rows-1 and not visited[row+1][col] and grid[row+1][col] != '1': new_dist = distance[curr] + 1 if (row+1, col) not in distance or new_dist < distance[(row+1, col)]: distance[(row+1, col)] = new_dist queue.append(((row+1, col), path + ['r5'])) visited[row+1][col] = True # No path found return None cgrid = [ [cb[i*50 + j] for j in range(50)] for i in range(50) ] def path_to_binary(path): binary = '' for move in path: if move == 'l1': binary += '00' if move == 'r1': binary += '01' if move == 'r5': binary += '11' if move == 'l5': binary += '10' return binary start = (49, 49) # 0th bit position end = (49, 47) # 2nd bit position path = find_shortest_path(start, end, cgrid) if path: print("Path found:", path) else: print("No path found.") print('Solution:', int(path_to_binary(path[::-1]), 2)) flag = (int(path_to_binary(path[::-1]), 2)%2**300) ^ 1565959740202953194497459354306763253658344353764229118098024096752495734667310309613713367 print(flag.to_bytes(flag.bit_length()//8+1, 'big')) ``` *Output:* ![](https://hackmd.io/_uploads/HyIakIDvn.gif) ## The game ʕノ•ᴥ•ʔノ ︵ ┻━┻ *PS: it's buggy and weird, made for visualization purposes* *PPS: Apologies for the bad code* ```python! import curses import locale from os import system, name def clear(): if name == 'nt': _ = system('cls') else: _ = system('clear') c = 211403263193325564935177732039311880968900585239198162576891024013795244278301418972476576250867590357558453818398439943850378531849394935408437463406454857158521417008852225672729172355559636113821448436305733721716196982836937454125646725644730318942728101471045037112450682284520951847177283496341601551774254483030077823813188507483073118602703254303097147462068515767717772884466792302813549230305888885204253788392922886375194682180491793001343169832953298914716055094436911057598304954503449174775345984866214515917257380264516918145147739699677733412795896932349404893017733701969358911638491238857741665750286105099248045902976635536517481599121390996091651261500380029994399838070532595869706503571976725974716799639715490513609494565268488194 cb = bin(c)[2:] def print_red(s, end='\n'): print("\033[91m{}\033[00m".format(s), end=end) def get_arrow_key(stdscr): key = stdscr.getch() if key == curses.KEY_LEFT: return 'l1' elif key == curses.KEY_RIGHT: return 'r1' elif key == curses.KEY_UP: return 'l5' elif key == curses.KEY_DOWN: return 'r5' else: return '' def removeredundancy(moves): last_four = moves[-4:] if last_four in ['0100', '0001', '1011', '1110']: return moves[:-4] return moves def printgrid(cb, curr): for i in range(50): for j in range(50): if (i*50 + j) == curr: print_red(cb[i*50 + j], end='') else: print(cb[i*50 + j], end='') print(' '*83, end='') # 83 because it fits my screen, adjust as needed def main(stdscr): curr = len(cb) - 1 moves = "" stdscr.nodelay(1) # Set non-blocking input mode # Set UTF-8 encoding locale.setlocale(locale.LC_ALL, '') stdscr.encoding = 'utf-8' while True: clear() # print(cb[:curr], end='') # print_red(cb[curr], end='') # print(cb[curr+1:]) # Commented out above code which was printing linearly, replaced with a function to print as a grid printgrid(cb, curr) moves = removeredundancy(moves) print(f'\n Moves so far: {moves}') move = '' while not move: move = get_arrow_key(stdscr) try: if move == 'l1': if cb[curr-1] == '1': print("Invalid move") continue curr -= 1 moves += '00' if move == 'r1': if cb[curr+1] == '1': print("Invalid move") continue curr += 1 moves += '01' if move == 'r5': if cb[curr+50] == '1': print("Invalid move") continue curr += 50 moves += '11' if move == 'l5': if cb[curr-50] == '1': print("Invalid move") continue curr -= 50 moves += '10' except KeyboardInterrupt: exit() except: pass curses.wrapper(main) ```

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully