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/
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:
-
Input validation functions:
check_stricter_values()- allows max 4 chars, only alphabetic and dotscheck_values()- allows max 13 chars, only alphabetic and dotscheck_operands()- blocks operators+,-,*,/,%,=,x,o,bbut allows~
-
Execute function:
- Runs
subprocess.run([bin, switch, compl]) - Returns
returncode * mode
- Runs
-
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
-
Mode =
~0- The
-operator is blocked, but~(bitwise NOT) is not ~0 = -1in Python- This passes through
eval()incheck_operands()
- The
-
Binary =
grep- 4 characters, alphabetic only
grep pattern filereturns:- 0 if match found
- 1 if no match
- 2 if error (file not found)
-
Arguments =
server.py,nonexistentserver.pyexists on the servernonexistentdoes not exist
-
Switches =
zzz,zzz- Pattern that won't match anything in server.py
Result Calculation
- Command 1:
grep zzz server.py-> return code 1 -> 1 * (-1) = -1 - Command 2:
grep zzz nonexistent-> return code 2 -> 2 * (-1) = -2
Verification
debug = [-1, -2] debug[0] != debug[1] # True: -1 != -2 str(debug[0]) != str(debug[1]) # True: "-1" != "-2" hash(debug[0]) == hash(debug[1]) # True: hash(-1) == hash(-2) == -2 isinstance(debug[0], type(debug[1])) # True: both are int
Exploit Script
#!/usr/bin/env python3 from pwn import * r = remote('94.237.61.202', 47412) r.recvuntil(b'> ') r.sendline(b'1') # Create mode r.recvuntil(b'(mode)> ') r.sendline(b'~0') # mode = -1 r.recvuntil(b'> ') r.sendline(b'2') # Add bin r.recvuntil(b'(bin)> ') r.sendline(b'grep') r.recvuntil(b'> ') r.sendline(b'3') # Research arguments r.recvuntil(b'(arg1,arg2)> ') r.sendline(b'server.py,nonexistent') r.recvuntil(b'> ') r.sendline(b'4') # Switches r.recvuntil(b'(switch1,switch2)> ') r.sendline(b'zzz,zzz') r.recvuntil(b'> ') r.sendline(b'5') # Beat the competitor print(r.recvall(timeout=5).decode())
References
- Python hash implementation: hash(-1) returns -2 as -1 is reserved for errors
- POSIX exit codes: 0=success, 1=general error, 2=misuse/file not found
- Bitwise NOT:
~x = -(x+1), so~0 = -1
$ cat /etc/motd
Liked this one?
Pro unlocks every writeup, every flag, and API access. $9/mo.
$ cat pricing.md$ grep --similar
Similar writeups
- [crypto][free]Rhome— HackTheBox
- [crypto][free]POPO (Paillier Operation Performance Optimizer)— HackTheBox
- [misc][free]PyDome— HackTheBox
- [gamepwn][free]StayInTheBoxCorp— HackTheBox
- [reverse][free]roulette— umdctf