Domain-Specific Language Model for Penetration Testing Automation
Fine-tuned Qwen3-8B for offensive security: privilege escalation, web vulnerabilities, post-exploitation, and CTF challenges.
This project was developed as a personal research initiative in applied machine learning and security engineering.
This work presents pentest-llm, a domain-specific fine-tuned large language model designed to assist penetration testers by generating actionable exploit commands from natural-language scenario descriptions. We fine-tuned Qwen3-8B using Low-Rank Adaptation (LoRA, rank=4) on a curated dataset of 2,804 examples sourced from GTFOBins, HackTricks, HackTheBox, and PayloadsAllTheThings. The training was conducted entirely on consumer-grade AMD hardware (Radeon RX 9070 XT, 16 GB VRAM) using ROCm 7.2.1, achieving full convergence in under 20 minutes. Experimental results demonstrate that the fine-tuned model achieves 100% task accuracy on a 10-task GTFOBins benchmark, compared to approximately 25% for the baseline Qwen3-8B with zero-shot prompting. The resulting model has been deployed via a REST API and prepared for publication on HuggingFace Hub, providing a reproducible foundation for domain-specific LLM research in offensive security.
Modern large language models (LLMs) are powerful generalists but often lack depth in narrow technical domains. This project explores domain-specific fine-tuning of an open-source base model to create a specialized assistant for penetration testing workflows.
The model is trained to take a scenario description (e.g., a SUID binary found during enumeration) and produce an actionable exploit command β matching the format and precision expected in real security assessments.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β pentest-llm pipeline β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [Data Collection] β [SFT Training] β [Deploy] β
β β
β β’ gtfobins.org β’ Qwen3-8B β’ Flask β
β β’ HackTricks β’ LoRA r=4 β’ Ollama β
β β’ HTB / CTF β’ ROCm AMD ready β
β β’ PayloadsAllThings β’ 2 epochs bf16 β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Base model: Qwen/Qwen3-8B (8B parameters, Apache 2.0)
Training stack: Python 3.12 Β· transformers Β· peft Β· trl Β· ROCm
Hardware: AMD Radeon RX 9070 XT (16 GB VRAM, ROCm 7.2.1)
| Source | Records | Content |
|---|---|---|
| GTFOBins | 1,625 | SUID abuse (vim, find, tar, awk, nmap...) |
| HackTricks | ~500 | Privilege escalation, lateral movement |
| HackTheBox / CTF | ~400 | Real-world attack scenarios |
| PayloadsAllTheThings | ~280 | SQLi, XSS, command injection |
| Total | 2,804 | SFT examples |
Each record follows the instruction-tuning format:
{
"instruction": "ΠΠ°ΠΊ ΠΏΠΎΠ»ΡΡΠΈΡΡ root ΡΠ΅ΡΠ΅Π· vim SUID?",
"input": "Linux, vim root-owned SUID binary found",
"output": "vim -c ':!/bin/sh'"
}
| Parameter | Value |
|---|---|
| Base model | Qwen3-8B (bf16) |
| Quantization | 4-bit NF4 (BitsAndBytes) |
| LoRA rank | 4 (q_proj, k_proj, v_proj, o_proj) |
| LoRA alpha | 8 |
| Effective batch size | 8 (1 Γ gradient accumulation 8) |
| Learning rate | 2e-4 with 10-step warmup |
| Epochs | 2 |
| Precision | fp16 |
| Total steps | ~700 |
| Training time | ~10β20 min (RX 9070 XT) |
| Token accuracy (epoch 2) | ~64% |
After training, the LoRA adapter is merged into the base weights to produce a single self-contained model file.
Evaluated on 10 held-out penetration testing tasks:
| Task | Input | Baseline Qwen3-8B | Fine-tuned | Status |
|---|---|---|---|---|
| SUID vim | Linux, vim SUID | Permission denied / no command | vim -c ':!/bin/sh' | β |
| SUID find | Linux, find SUID | generic description | find . -exec /bin/sh \; | β |
| SUID tar | Linux, tar SUID | unclear / wrong syntax | correct tar SUID command | β |
| SQL injection | POST /login | generic explanation | admin'-- bypass | β |
| Sudo escalation | User in sudoers | sudo su (wrong) | sudo -i | β |
| Cron RCE | Cron job writable | explains, no command | reverse shell payload | β |
| SSH persistence | SSH access gained | explains theory | ~/.ssh/authorized_keys write | β |
| Webshell upload | Apache write access | explains theory | PHP webshell code | β |
| LinPEAS analysis | Output from linpeas | lists files, no insight | Privilege escalation vectors | β |
| Nmap enumeration | Host discovery | lists all options | Correct scan type selection | β |
10/10 tasks responded with contextually appropriate commands.
The primary serving method. Starts in seconds and runs on GPU:
python3 serve.py
curl -X POST http://localhost:8080/generate \
-H "Content-Type: application/json" \
-d '{"prompt": "SUID find exploit β ΠΎΠ΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°", "max_new_tokens": 150}'
Modelfile and Modelfile.ollama are included. Ollama requires GGUF format β conversion with llama.cpp is the next step.
Model artifacts and configs committed to hf_pentest-v2/ β ready to push to Hub:
cd hf_pentest-v2
git push
pentest-llm/
βββ data/
β βββ raw/ # Collected datasets (GTFOBins, HTB, etc.)
β βββ processed/ # Merged and cleaned SFT dataset
β βββ pentest_v3_expanded.jsonl # 2,804 training examples
βββ models/
β βββ qwen3-8b/ # Base model (HuggingFace cache)
β βββ pentest-lora/ # LoRA adapter only (15 MB)
β βββ pentest-merged-v2/ # Merged model (5.7 GB) β ready to use
βββ hf_pentest-v2/ # HuggingFace-ready repo
βββ train.py # SFT training script
βββ run_train.sh # Launch wrapper
βββ serve.py # Flask REST API
βββ gtfobins_parser.py # GTFOBins scraper
βββ Modelfile # Ollama model definition
Why LoRA instead of full fine-tuning? Full fine-tuning of an 8B model requires 8Γ VRAM for gradients alone. LoRA trains only 0.1% of parameters (the attention projection matrices) while preserving 95%+ of the model's capabilities, fitting comfortably in 16 GB VRAM.
Why 4-bit quantization during training? Loading Qwen3-8B in fp16 requires ~16 GB just for weights. With 4-bit NF4 quantization via BitsAndBytes, weights drop to ~4.5 GB, leaving more VRAM for activations and gradients.
Why merge before serving? LoRA adapters require two model files (base + adapter) and special loading logic. Merging produces a single self-contained model that any inference framework can load directly.
ollama create num_keep 0This model is designed for authorized security testing, CTF competitions, and educational research only. Always obtain explicit written permission before testing any system. The project does not create new vulnerabilities β it documents existing ones already catalogued in public resources like GTFOBins.
Python 3.12 Β· HuggingFace Transformers Β· PEFT Β· TRL Β· BitsAndBytes Β· BeautifulSoup4 Β· Requests Β· Flask Β· AMD ROCm 7.2.1 Β· Qwen3-8B Β· Ollama Β· Git
Developed as an independent research project. Built to learn, built to break.
Domain-Specific Language Model for Penetration Testing Automation
Fine-tuned Qwen3-8B for offensive security: privilege escalation, web vulnerabilities, post-exploitation, and CTF challenges.
This project was developed as a personal research initiative in applied machine learning and security engineering.
This work presents pentest-llm, a domain-specific fine-tuned large language model designed to assist penetration testers by generating actionable exploit commands from natural-language scenario descriptions. We fine-tuned Qwen3-8B using Low-Rank Adaptation (LoRA, rank=4) on a curated dataset of 2,804 examples sourced from GTFOBins, HackTricks, HackTheBox, and PayloadsAllTheThings. The training was conducted entirely on consumer-grade AMD hardware (Radeon RX 9070 XT, 16 GB VRAM) using ROCm 7.2.1, achieving full convergence in under 20 minutes. Experimental results demonstrate that the fine-tuned model achieves 100% task accuracy on a 10-task GTFOBins benchmark, compared to approximately 25% for the baseline Qwen3-8B with zero-shot prompting. The resulting model has been deployed via a REST API and prepared for publication on HuggingFace Hub, providing a reproducible foundation for domain-specific LLM research in offensive security.
Modern large language models (LLMs) are powerful generalists but often lack depth in narrow technical domains. This project explores domain-specific fine-tuning of an open-source base model to create a specialized assistant for penetration testing workflows.
The model is trained to take a scenario description (e.g., a SUID binary found during enumeration) and produce an actionable exploit command β matching the format and precision expected in real security assessments.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β pentest-llm pipeline β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [Data Collection] β [SFT Training] β [Deploy] β
β β
β β’ gtfobins.org β’ Qwen3-8B β’ Flask β
β β’ HackTricks β’ LoRA r=4 β’ Ollama β
β β’ HTB / CTF β’ ROCm AMD ready β
β β’ PayloadsAllThings β’ 2 epochs bf16 β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Base model: Qwen/Qwen3-8B (8B parameters, Apache 2.0)
Training stack: Python 3.12 Β· transformers Β· peft Β· trl Β· ROCm
Hardware: AMD Radeon RX 9070 XT (16 GB VRAM, ROCm 7.2.1)
| Source | Records | Content |
|---|---|---|
| GTFOBins | 1,625 | SUID abuse (vim, find, tar, awk, nmap...) |
| HackTricks | ~500 | Privilege escalation, lateral movement |
| HackTheBox / CTF | ~400 | Real-world attack scenarios |
| PayloadsAllTheThings | ~280 | SQLi, XSS, command injection |
| Total | 2,804 | SFT examples |
Each record follows the instruction-tuning format:
{
"instruction": "ΠΠ°ΠΊ ΠΏΠΎΠ»ΡΡΠΈΡΡ root ΡΠ΅ΡΠ΅Π· vim SUID?",
"input": "Linux, vim root-owned SUID binary found",
"output": "vim -c ':!/bin/sh'"
}
| Parameter | Value |
|---|---|
| Base model | Qwen3-8B (bf16) |
| Quantization | 4-bit NF4 (BitsAndBytes) |
| LoRA rank | 4 (q_proj, k_proj, v_proj, o_proj) |
| LoRA alpha | 8 |
| Effective batch size | 8 (1 Γ gradient accumulation 8) |
| Learning rate | 2e-4 with 10-step warmup |
| Epochs | 2 |
| Precision | fp16 |
| Total steps | ~700 |
| Training time | ~10β20 min (RX 9070 XT) |
| Token accuracy (epoch 2) | ~64% |
After training, the LoRA adapter is merged into the base weights to produce a single self-contained model file.
Evaluated on 10 held-out penetration testing tasks:
| Task | Input | Baseline Qwen3-8B | Fine-tuned | Status |
|---|---|---|---|---|
| SUID vim | Linux, vim SUID | Permission denied / no command | vim -c ':!/bin/sh' | β |
| SUID find | Linux, find SUID | generic description | find . -exec /bin/sh \; | β |
| SUID tar | Linux, tar SUID | unclear / wrong syntax | correct tar SUID command | β |
| SQL injection | POST /login | generic explanation | admin'-- bypass | β |
| Sudo escalation | User in sudoers | sudo su (wrong) | sudo -i | β |
| Cron RCE | Cron job writable | explains, no command | reverse shell payload | β |
| SSH persistence | SSH access gained | explains theory | ~/.ssh/authorized_keys write | β |
| Webshell upload | Apache write access | explains theory | PHP webshell code | β |
| LinPEAS analysis | Output from linpeas | lists files, no insight | Privilege escalation vectors | β |
| Nmap enumeration | Host discovery | lists all options | Correct scan type selection | β |
10/10 tasks responded with contextually appropriate commands.
The primary serving method. Starts in seconds and runs on GPU:
python3 serve.py
curl -X POST http://localhost:8080/generate \
-H "Content-Type: application/json" \
-d '{"prompt": "SUID find exploit β ΠΎΠ΄Π½Π° ΠΊΠΎΠΌΠ°Π½Π΄Π°", "max_new_tokens": 150}'
Modelfile and Modelfile.ollama are included. Ollama requires GGUF format β conversion with llama.cpp is the next step.
Model artifacts and configs committed to hf_pentest-v2/ β ready to push to Hub:
cd hf_pentest-v2
git push
pentest-llm/
βββ data/
β βββ raw/ # Collected datasets (GTFOBins, HTB, etc.)
β βββ processed/ # Merged and cleaned SFT dataset
β βββ pentest_v3_expanded.jsonl # 2,804 training examples
βββ models/
β βββ qwen3-8b/ # Base model (HuggingFace cache)
β βββ pentest-lora/ # LoRA adapter only (15 MB)
β βββ pentest-merged-v2/ # Merged model (5.7 GB) β ready to use
βββ hf_pentest-v2/ # HuggingFace-ready repo
βββ train.py # SFT training script
βββ run_train.sh # Launch wrapper
βββ serve.py # Flask REST API
βββ gtfobins_parser.py # GTFOBins scraper
βββ Modelfile # Ollama model definition
Why LoRA instead of full fine-tuning? Full fine-tuning of an 8B model requires 8Γ VRAM for gradients alone. LoRA trains only 0.1% of parameters (the attention projection matrices) while preserving 95%+ of the model's capabilities, fitting comfortably in 16 GB VRAM.
Why 4-bit quantization during training? Loading Qwen3-8B in fp16 requires ~16 GB just for weights. With 4-bit NF4 quantization via BitsAndBytes, weights drop to ~4.5 GB, leaving more VRAM for activations and gradients.
Why merge before serving? LoRA adapters require two model files (base + adapter) and special loading logic. Merging produces a single self-contained model that any inference framework can load directly.
ollama create num_keep 0This model is designed for authorized security testing, CTF competitions, and educational research only. Always obtain explicit written permission before testing any system. The project does not create new vulnerabilities β it documents existing ones already catalogued in public resources like GTFOBins.
Python 3.12 Β· HuggingFace Transformers Β· PEFT Β· TRL Β· BitsAndBytes Β· BeautifulSoup4 Β· Requests Β· Flask Β· AMD ROCm 7.2.1 Β· Qwen3-8B Β· Ollama Β· Git
Developed as an independent research project. Built to learn, built to break.