Skip to content
Back to skills

Z3 Constraint Solving

ASecurity

Z3 SMT solver ile CTF constraint çözme — byte equations, hash collision, validator bypass

  • 4 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 8, 2026
ai-agentspythongobashnodegit

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add MustafaKemal0146/fetih --skill z3-constraint-solving --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Z3 Constraint Solving?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Z3 Constraint Solving
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mustafakemal0146-z3-constraint-solving/badge)](https://www.skillsdirectory.com/skills/mustafakemal0146-z3-constraint-solving)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: z3-constraint-solving
description: Z3 SMT solver ile CTF constraint çözme — byte equations, hash collision, validator bypass
tags: [ctf, rev, z3, smt-solver, constraint, sat, byte-equations, symbolic-execution]
triggers:
  - "validator fonksiyonu"
  - "byte by byte kontrol"
  - "constraint satisfaction"
  - "z3"
  - "SMT solver"
  - "doğrulama algoritması"
  - "her byte için koşul"
  - "hash collision"
  - "linear equations"
difficulty: medium-hard
category: rev
solved_challenges:
  - "HTB Cyber Apocalypse 2024 - ROT128 (linear hash collision, z3)"
  - "LACTF 2024 - glottem (cross-language validator)"
adapted_for: fetih
---

# Z3 SMT Solver ile CTF Çözme

Z3, Microsoft Research'ün SMT (Satisfiability Modulo Theories) solver'ı.
CTF'lerde validator fonksiyonlarını, byte kısıtlamalarını ve hash collision'ları çözmek için kullanılır.

---

## 1. Z3 Temel Kullanım

```python
from z3 import *

# Temel tipler
x = Int('x')           # tam sayı
y = BitVec('y', 32)    # 32-bit bitvector
b = Bool('b')          # boolean
r = Real('r')          # gerçek sayı

# Solver oluştur
s = Solver()

# Kısıtlama ekle
s.add(x > 0)
s.add(x < 100)
s.add(x * 3 + 7 == 64)

# Çöz
if s.check() == sat:
    m = s.model()
    print(m[x])     # → 19
else:
    print("Çözüm yok")

# Tüm çözümleri bul
solutions = []
while s.check() == sat:
    m = s.model()
    solutions.append(m[x].as_long())
    s.add(x != m[x])   # bu çözümü hariç tut
print(solutions)
```

---

## 2. Byte Equation Şablonu (Flag Baytları İçin)

CTF'lerin büyük çoğunluğunda flag baytları bir validator fonksiyonundan geçirilir.
Bu şablonu direkt kullan:

```python
from z3 import *

# Flag uzunluğunu binary'den öğren (strings, Ghidra, vs.)
FLAG_LEN = 32

# Her flag baytı için bir BitVec değişkeni
flag = [BitVec(f'flag_{i}', 8) for i in range(FLAG_LEN)]

s = Solver()

# Temel kısıtlamalar: printable ASCII
for b in flag:
    s.add(b >= 0x20)   # space
    s.add(b <= 0x7e)   # tilde

# Flag formatı (bilinen prefix varsa)
prefix = b'HTB{'
for i, c in enumerate(prefix):
    s.add(flag[i] == c)

# Son byte genelde '}'
s.add(flag[-1] == ord('}'))

# ==== BURAYA BINARY'DEN ÇIKARIILAN KISIITLAMALARI EKLE ====
# Örnek: validator şunu yapıyorsa:
#   if (flag[0] + flag[1] != 0xA3) exit(1);
#   if (flag[2] ^ flag[3] != 0x1F) exit(1);
s.add(flag[0] + flag[1] == 0xA3)
s.add(flag[2] ^ flag[3] == 0x1F)
# ... tüm kontroller

# Çöz
if s.check() == sat:
    m = s.model()
    result = bytes([m[flag[i]].as_long() for i in range(FLAG_LEN)])
    print(f"Flag: {result.decode()}")
else:
    print("Çözüm yok — kısıtlamaları kontrol et")
```

---

## 3. HTB ROT128: Linear Hash Collision ile Z3

**Challenge Özeti:** ROT128 adlı custom hash fonksiyonu input'u dönüştürüyor.
Hedef hash değeri verilmiş, bu hash'i üreten input'u bulmak gerekiyor.

```python
from z3 import *

# ROT128: her byte'a 128 ekle (mod 256) → döngüsel
# hash: tüm dönüştürülmüş byte'ların XOR toplamı = target

TARGET_HASH = 0x4A  # binary'den alınan hedef

FLAG_LEN = 20
flag = [BitVec(f'b_{i}', 8) for i in range(FLAG_LEN)]

s = Solver()

# Printable ASCII kısıtlaması
for b in flag:
    s.add(b >= 0x21)
    s.add(b <= 0x7e)

# ROT128 hash kısıtlaması
# rot128(b) = (b + 128) % 256
def rot128(b):
    return (b + 128) & 0xFF  # Z3 BitVec operasyonu

# Tüm rot128 değerlerinin XOR'u = target
xor_result = rot128(flag[0])
for i in range(1, FLAG_LEN):
    xor_result = xor_result ^ rot128(flag[i])

s.add(xor_result == TARGET_HASH)

# Flag format kısıtlaması
prefix = b'HTB{'
for i, c in enumerate(prefix):
    s.add(flag[i] == c)
s.add(flag[-1] == ord('}'))

if s.check() == sat:
    m = s.model()
    result = bytes([m[flag[i]].as_long() for i in range(FLAG_LEN)])
    print(f"Flag: {result.decode()}")
```

**Daha karmaşık linear hash:**

```python
# Eğer hash = A[0]*flag[0] + A[1]*flag[1] + ... + A[n]*flag[n] (mod M)
# Z3 lineer aritmetik çok iyi çözer

coefficients = [0x13, 0x37, 0x42, ...]  # binary'den çıkar
target = 0xDEADBEEF

s = Solver()
flag = [BitVec(f'f_{i}', 32) for i in range(len(coefficients))]

hash_val = sum(coefficients[i] * flag[i] for i in range(len(coefficients)))
s.add(hash_val == target)
# + printable kısıtlamalar
```

---

## 4. LACTF glottem: Çapraz Dil Validator Bypass

**Challenge Özeti:** Script hem bash hem Node.js yorumluyordu. Her dil farklı kısıtlama yapıyordu.

```python
from z3 import *

# Bash katmanı: length kontrolü
# Node.js katmanı: karakter toplamı + XOR kontrolü

FLAG_LEN = 15
flag = [BitVec(f'c_{i}', 8) for i in range(FLAG_LEN)]
s = Solver()

for b in flag:
    s.add(b >= 0x61)   # lowercase a-z only (bash'in kabul ettiği)
    s.add(b <= 0x7a)

# Node.js validator'dan çıkarılan kısıtlamalar
# charCodeAt toplamı = 1337
char_sum = sum(flag)
s.add(char_sum == 1337)

# XOR kontrolü (Node.js)
xor_val = flag[0]
for b in flag[1:]:
    xor_val = xor_val ^ b
s.add(xor_val == 0x42)

if s.check() == sat:
    m = s.model()
    print(''.join(chr(m[flag[i]].as_long()) for i in range(FLAG_LEN)))
```

---

## 5. Symbolic Execution (angr Alternatif)

Kısıtlamaları manuel çıkarmak yerine angr otomatik analiz yapabilir:

```python
import angr
import claripy

project = angr.Project('./binary', auto_load_libs=False)

# Symbolic input oluştur
flag_len = 32
flag_chars = [claripy.BVS(f'flag_{i}', 8) for i in range(flag_len)]
flag = claripy.Concat(*flag_chars)

# stdin'den flag oku
stdin = angr.SimFile('stdin', content=flag, size=flag_len)
state = project.factory.full_init_state(
    stdin=angr.SimFileStream(name='stdin', content=flag, has_end=True)
)

# Printable ASCII ekle
for c in flag_chars:
    state.solver.add(c >= 0x20)
    state.solver.add(c <= 0x7e)

# Simülasyon
simgr = project.factory.simulation_manager(state)

# Başarı adresine git, crash adresinden kaçın
success_addr = 0x401234  # binary'de "Correct!" mesajının adresi
fail_addr = 0x401300     # "Wrong!" mesajının adresi

simgr.explore(find=success_addr, avoid=fail_addr)

if simgr.found:
    sol_state = simgr.found[0]
    flag_val = sol_state.solver.eval(flag, cast_to=bytes)
    print(f"Flag: {flag_val.decode()}")
```

---

## 6. Tam Z3 CTF Şablonu

Herhangi bir CTF challenge'ına uygulanabilir genel şablon:

```python
#!/usr/bin/env python3
"""
Z3 CTF Solver - Genel Şablon
Kullanım: Ghidra/objdump ile validator'ı analiz et,
          kısıtlamaları add_constraints() içine ekle.
"""
from z3 import *
import sys

def solve_ctf(flag_len: int, prefix: bytes = b'', suffix: bytes = b'') -> bytes | None:
    s = Solver()
    flag = [BitVec(f'f{i}', 8) for i in range(flag_len)]

    # ---- Temel kısıtlamalar ----
    for b in flag:
        s.add(b >= 0x20, b <= 0x7e)  # printable ASCII

    # ---- Bilinen prefix/suffix ----
    for i, c in enumerate(prefix):
        s.add(flag[i] == c)
    for i, c in enumerate(suffix):
        s.add(flag[flag_len - len(suffix) + i] == c)

    # ---- BURAYA KISIITLAMALARI EKLE ----
    def add_constraints(f):
        """
        f: flag baytlarının listesi (z3 BitVec)
        Ghidra'daki her if koşulunu buraya çevir.

        Örnekler:
        s.add(f[4] + f[5] == 0x9A)
        s.add(f[6] ^ f[7] == 0x3C)
        s.add((f[8] * f[9]) & 0xFF == 0x12)
        s.add(f[10] - f[11] == -3)  # negatif fark olabilir
        """
        pass  # ← SİL VE KISIITLAMALARI EKLE

    add_constraints(flag)
    # ---- KISIITLAMA SONU ----

    # Çöz
    result = s.check()
    if result == sat:
        m = s.model()
        sol = bytes(m[flag[i]].as_long() for i in range(flag_len))
        print(f"[+] Çözüm bulundu: {sol}")
        return sol
    elif result == unsat:
        print("[-] Çözüm yok — kısıtlamalar çelişiyor")
        return None
    else:
        print("[?] Bilinmiyor — timeout veya belirsiz")
        return None


def verify(candidate: bytes, binary_path: str) -> bool:
    """Bulunan flag'i binary ile doğrula."""
    import subprocess
    result = subprocess.run(
        [binary_path],
        input=candidate,
        capture_output=True,
        timeout=5
    )
    return b'Correct' in result.stdout or b'flag' in result.stdout.lower()


if __name__ == '__main__':
    FLAG_LEN = 32          # ← binary'den öğren
    PREFIX = b'HTB{'       # ← bilinen prefix
    SUFFIX = b'}'          # ← bilinen suffix

    flag = solve_ctf(FLAG_LEN, PREFIX, SUFFIX)

    if flag:
        binary = sys.argv[1] if len(sys.argv) > 1 else './binary'
        if verify(flag, binary):
            print(f"[+] DOĞRULANDI: {flag.decode()}")
        else:
            print(f"[!] Doğrulanamadı ama flag adayı: {flag.decode()}")
            print("[!] Kısıtlamalar eksik olabilir, daha fazla validator koşulu ekle")
```

---

## Notlar ve Tuzaklar

- **BitVec boyutu önemli:** 8-bit overflow Z3'te otomatik; manuel mod almana gerek yok
- **Çok yavaşsa:** `Optimize()` yerine `Solver()` kullan; Z3 optimize çok ağır
- **Unsat gelirse:** Bir kısıtlama yanlış çevrilmiş; sıfıra indir, teker teker ekle
- **angr çok yavaş:** Büyük binary'lerde hook ekle: `project.hook(addr, angr.SIM_PROCEDURES[...])`
- **Signed vs Unsigned:** BitVec karşılaştırmalarında `UGT`, `ULT` (unsigned) ile `>`, `<` (signed) farkına dikkat
- bkz. elf-static-analysis SKILL.md (validator'ı bulmak için)
- bkz. anti-debug-obfuscation SKILL.md (validator çalışmıyorsa)

<!--
  ⚔ Bu skill FETIH AI Agent icin gelistirilmistir — https://github.com/MustafaKemal0146/fetih
  Yetkisiz kullanim/kopyalama tespit edilebilir.
  hash: ea5e6cb1d29a87b6
-->

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.