Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions byuctf-2026/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
**/.gdb_history

### Python ###
# Byte-compiled / optimized / DLL files
**/__pycache__/
**/*.py[cod]
**/*$py.class

# C extensions
**/*.so

# Distribution / packaging
**/.Python
**/build/
**/develop-eggs/
**/dist/
**/downloads/
**/eggs/
**/.eggs/
**/lib/
**/lib64/
**/parts/
**/sdist/
**/var/
**/wheels/
**/share/python-wheels/
**/*.egg-info/
**/.installed.cfg
**/*.egg
**/MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
**/*.manifest
**/*.spec

# Installer logs
**/pip-log.txt
**/pip-delete-this-directory.txt

# Unit test / coverage reports
**/htmlcov/
**/.tox/
**/.nox/
**/.coverage
**/.coverage.*
**/.cache
**/nosetests.xml
**/coverage.xml
**/*.cover
**/*.py,cover
**/.hypothesis/
**/.pytest_cache/
**/cover/

# Translations
**/*.mo
**/*.pot

# Django stuff:
**/*.log
**/local_settings.py
**/db.sqlite3
**/db.sqlite3-journal

# Flask stuff:
**/instance/
**/.webassets-cache

# Scrapy stuff:
**/.scrapy

# Sphinx documentation
**/docs/_build/

# PyBuilder
**/.pybuilder/
**/target/

# Jupyter Notebook
**/.ipynb_checkpoints

# IPython
**/profile_default/
**/ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
**/.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
**/__pypackages__/

# Celery stuff
**/celerybeat-schedule
**/celerybeat.pid

# SageMath parsed files
**/*.sage.py

# Environments
**/.env
**/.venv
**/env/
**/venv/
**/ENV/
**/env.bak/
**/venv.bak/

# Spyder project settings
**/.spyderproject
**/.spyproject

# Rope project settings
**/.ropeproject

# mkdocs documentation
**/site

# mypy
**/.mypy_cache/
**/.dmypy.json
**/dmypy.json

# Pyre type checker
**/.pyre/

# pytype static type analyzer
**/.pytype/

# Cython debug symbols
**/cython_debug/

### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
**/poetry.toml

# ruff
**/.ruff_cache/
3 changes: 3 additions & 0 deletions byuctf-2026/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# BYUCTF 2026

- **Event:** [BYUCTF 2026](https://chals.cyberjousting.com) ([CTFTime](https://ctftime.org/event/3247/))
9 changes: 9 additions & 0 deletions byuctf-2026/pwn/heap2win/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM fedora:42

RUN dnf install -y socat libstdc++ && dnf clean all

COPY heap2win /heap2win
RUN chmod +x /heap2win

EXPOSE 9001
CMD ["socat", "TCP-LISTEN:9001,reuseaddr,fork", "EXEC:/heap2win,stderr"]
45 changes: 45 additions & 0 deletions byuctf-2026/pwn/heap2win/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Writeup: heap2win (BYUCTF 2026)

- **Event:** [BYUCTF 2026](https://chals.cyberjousting.com) ([CTFTime](https://ctftime.org/event/3247/))
- **Challenge:** heap2win
- **Category:** Pwn
- **Remote:** `chals.cyberjousting.com:1364`

The challenge ships a C++ binary and the full source in `main.cpp`. The program is a small "button factory" where you can create buttons and push them. Each button type is a subclass of `Button` with a virtual `push()` method. The goal is to get code execution; the interesting class is `WinnerButton`, which calls `system("/bin/sh")` when pushed.

## Initial Analysis

The menu lets you create a **Hype Button** or a **Custom Button**. Creating a **Winner Button** is explicitly blocked with a message telling you that you are not a winner yet. However, `main()` allocates a `WinnerButton` on the heap before the application loop starts:

```cpp
WinnerButton *but = new WinnerButton();
Application *app = new Application();
app->run();
```

That object is never added to the application's `button_list`, but its vtable still exists in the binary at a fixed address (no PIE).

`CustomButton` reads the button name with `scanf("%s", name)` into a `char name[0x10]` member. There is no length limit, so any name longer than 16 bytes overflows the heap allocation for the `CustomButton` object and corrupts whatever chunk comes next.

The application keeps `Button*` pointers in a `std::vector`. When the vector grows, it reallocates its internal pointer array and frees the old array. After creating two `HypeButton` objects, adding a third button triggers a reallocation. The next `CustomButton` allocation can land in the freed vector storage, adjacent to the second `HypeButton` on the heap. Overflowing the custom name then overwrites the second hype button's chunk metadata and vtable pointer.

## Binary Security

```
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
```

Full RELRO means we cannot overwrite GOT entries. NX rules out shellcode on the heap. Without PIE, vtable addresses and the `WinnerButton` vtable at `0x403640` are fixed. The exploit path is a vtable hijack on an object we can still call through `pushButton()`.

## Solution

The exploit in `solve.py` follows these steps:

1. Create two `HypeButton` instances so the vector reallocates and the heap layout places the upcoming `CustomButton` next to hype button #2.
2. Create a `CustomButton` and send a 32-byte name: 16 bytes of padding (fills the `name` field), 8 bytes set to `0x21` (keeps the adjacent malloc chunk header plausible), and 8 bytes pointing to `WinnerButton`'s vtable (`0x403640`).
3. Push button index 2. The program calls `push()` on what it still thinks is a `HypeButton`, but the vtable now dispatches to `WinnerButton::push()`, which runs `system("/bin/sh")`.
5 changes: 5 additions & 0 deletions byuctf-2026/pwn/heap2win/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
services:
heap2win:
build: .
ports:
- "9001:9001"
Binary file added byuctf-2026/pwn/heap2win/heap2win
Binary file not shown.
3 changes: 3 additions & 0 deletions byuctf-2026/pwn/heap2win/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
HYPE HYPE HYPE

chals.cyberjousting.com:1364
Loading