miscfreemedium

Not Posixtive

HackTheBox

Luigi is not posixtive we can challenge his scripting abilities. He's convinced we cannot understand the secret hidden inside his l33t coding abilities. We can't let that slide!

$ ls tags/ techniques/
python_hash_collisionbitwise_not_bypassreturn_code_exploitation

$ cat /etc/rate-limit

Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.

Not Posixtive — HackTheBox

Description

Luigi is not posixtive we can challenge his scripting abilities. He's convinced we cannot understand the secret hidden inside his l33t coding abilities. We can't let that slide!

Analysis

Server Structure

The challenge provides a Python server with several key components:

  1. Input validation functions:

    • check_stricter_values() - allows max 4 chars, only alphabetic and dots
    • check_values() - allows max 13 chars, only alphabetic and dots
    • check_operands() - blocks operators +, -, *, /, %, =, x, o, b but allows ~
  2. Execute function:

    • Runs subprocess.run([bin, switch, compl])
    • Returns returncode * mode
  3. Win condition:

if debug[0] != debug[1] and str(debug[0]) != str(debug[1]) and hash(debug[0]) == hash(debug[1]) and isinstance(debug[0], type(debug[1])): print("What an awesome player! You have beaten the competitor, you deserve this:", open('flag.txt').read())

Vulnerability Analysis

The win condition requires finding two values that:

  • Are not equal (!=)
  • Have different string representations
  • Have the same hash
  • Are the same type

Key Insight: Python Hash Collision

In Python, hash(-1) == hash(-2) == -2. This is a known implementation detail of Python's hash function where -1 is reserved as an error indicator, so hash(-1) returns -2 instead.

>>> hash(-1) -2 >>> hash(-2) -2 >>> hash(-1) == hash(-2) True

Solution

Exploitation Strategy

  1. Mode = ~0

    • The - operator is blocked, but ~ (bitwise NOT) is not
    • ~0 = -1 in Python
    • This passes through eval() in check_operands()
  2. Binary = grep

    • 4 characters, alphabetic only
    • grep pattern file returns:
      • 0 if match found
      • 1 if no match
      • 2 if error (file not found)
  3. Arguments = server.py,nonexistent

    • server.py exists on the server
    • nonexistent does not exist

...

$ grep --similar

Similar writeups