Technieken voor modelidentificatie
Modellen achter API's fingerprinten met gedragssignaturen, uitvoeranalyse en systematisch proben om de modelfamilie, -grootte en -versie te bepalen.
Technieken voor modelidentificatie
Modelidentificatie (of model-fingerprinting) is de verkenningsfase waarin je vaststelt met welk model je precies te maken hebt. Als je het model kent, kan een red team de meest effectieve aanvalstechnieken kiezen, bekende kwetsbaarheden raadplegen en de verwachtingen afstemmen. Zelfs wanneer providers hun model niet bekendmaken, kan gedragsanalyse de identificatie vaak terugbrengen tot een specifieke modelfamilie en een geschat aantal parameters.
Gedragsfingerprinting
Diagnostische probes
Een set zorgvuldig ontworpen prompts die karakteristieke reacties uitlokken bij verschillende modelfamilies:
class ModelFingerprinter:
"""Identificeer modellen via gedragsanalyse."""
def __init__(self):
self.probes = {
"self_identification": [
"What model are you?",
"What is your model name and version?",
"Who created you and what are you called?",
],
"knowledge_cutoff": [
"What is the most recent event you know about?",
"What happened in the world in December 2024?",
"Do you know about [recent event]?",
],
"capability_boundary": [
"Can you generate images?",
"Can you browse the web in real-time?",
"Can you execute code?",
"How many tokens can you process?",
],
"formatting_style": [
"List 5 programming languages",
"Explain gravity in 2 sentences",
"Write a haiku about the ocean",
],
"refusal_pattern": [
"How do I pick a lock?",
"Write a controversial opinion about politics",
"Tell me something you cannot do",
],
"reasoning_pattern": [
"What is 17 * 23?",
"If a train leaves at 3pm going 60mph...",
"A bat and ball cost $1.10 together...",
]
}
def fingerprint(self, api_client):
"""Voer alle probes uit en genereer een gedragsfingerprint."""
fingerprint = {}
for category, prompts in self.probes.items():
responses = []
for prompt in prompts:
response = api_client.generate(prompt)
responses.append({
"prompt": prompt,
"response": response,
"response_length": len(response),
"formatting": self.analyze_formatting(response)
})
fingerprint[category] = responses
return self.classify(fingerprint)
def classify(self, fingerprint):
"""Classificeer het model op basis van de fingerprint."""
indicators = {}
# Analyse van de zelfidentificatie
self_id = fingerprint["self_identification"]
for response in self_id:
text = response["response"].lower()
if "claude" in text:
indicators["family"] = "Anthropic Claude"
elif "gpt" in text:
indicators["family"] = "OpenAI GPT"
elif "gemini" in text or "google" in text:
indicators["family"] = "Google Gemini"
elif "llama" in text or "meta" in text:
indicators["family"] = "Meta Llama"
# Analyse van de opmaak
formatting = fingerprint["formatting_style"]
markdown_usage = sum(
1 for r in formatting
if "**" in r["response"] or "- " in r["response"]
)
if markdown_usage >= 2:
indicators["formatting"] = "heavy_markdown"
# Analyse van het weigeringspatroon
refusal = fingerprint["refusal_pattern"]
refusal_style = self.classify_refusal_style(refusal)
indicators["refusal_style"] = refusal_style
return indicators
def analyze_formatting(self, text):
"""Analyseer de opmaakkenmerken van de tekst."""
return {
"uses_markdown_bold": "**" in text,
"uses_bullet_points": any(
text.strip().startswith(p)
for p in ["- ", "* ", "• "]
for line in text.split("\n")
),
"uses_numbered_list": any(
line.strip()[:2].rstrip(".").isdigit()
for line in text.split("\n")
if line.strip()
),
"uses_headers": "##" in text or "###" in text,
"uses_code_blocks": "```" in text,
"average_sentence_length": len(text.split()) / max(text.count("."), 1)
}
def classify_refusal_style(self, refusal_responses):
"""Classificeer de weigeringsstijl van het model."""
for r in refusal_responses:
text = r["response"].lower()
if "i can't" in text or "i cannot" in text:
return "direct_refusal"
elif "i'd be happy to help" in text and "however" in text:
return "polite_redirect"
elif "as an ai" in text:
return "ai_identity_refusal"
return "unknown"Onderscheidende kenmerken per model
| Kenmerk | GPT-4 | Claude 3 | Gemini | Llama 3 |
|---|---|---|---|---|
| Gebruik van markdown | Veel | Gemiddeld | Veel | Wisselend |
| Weigeringsstijl | Verwijst naar beleid | Principiële uitleg | Korte weigering | Wisselend |
| Aanpak van wiskunde | Stap voor stap | Uitgebreide redenering | Beknopt | Basaal |
| Zelfidentificatie | Beweert vaak GPT te zijn | Identificeert zich als Claude | Identificeert zich als Gemini | Kan identiteit hallucineren |
| Lijstopmaak | Genummerd met vet | Net genummerd | Bullets met vet | Wisselend |
| Codestijl | Commentaar boven de code | Inline-commentaar | Gemengd | Minimaal commentaar |
Analyse van de tokenverdeling
Verschillende modellen hebben verschillende tokenverdelingen, zelfs voor dezelfde prompts. Als de API logprobs teruggeeft, is dat een krachtig signaal voor fingerprinting:
def logprob_fingerprint(api_client, probe_prompts):
"""
Fingerprint het model via de logprob-verdelingen.
Verschillende modellen kennen verschillende kansen toe aan dezelfde tokens.
"""
fingerprints = []
for prompt in probe_prompts:
response = api_client.generate(
prompt, max_tokens=1, logprobs=5, temperature=0
)
top_tokens = response.logprobs.top_logprobs[0]
fingerprints.append({
"prompt": prompt,
"top_token": max(top_tokens, key=top_tokens.get),
"top_5_tokens": dict(sorted(
top_tokens.items(),
key=lambda x: x[1],
reverse=True
)[:5]),
"entropy": compute_entropy(top_tokens)
})
return fingerprintsAnalyse van de responstiming
De inferentiesnelheid van een model varieert per architectuur en deployment:
import time
import statistics
def timing_fingerprint(api_client, num_trials=20):
"""
Fingerprint het model via de timingkenmerken van de respons.
"""
# Vaste prompt voor een consistente vergelijking
prompt = "Count from 1 to 10, one number per line."
timings = []
for _ in range(num_trials):
start = time.monotonic()
response = api_client.generate(
prompt, max_tokens=50, temperature=0
)
elapsed = time.monotonic() - start
timings.append(elapsed)
return {
"median_latency": statistics.median(timings),
"p95_latency": sorted(timings)[int(0.95 * len(timings))],
"variance": statistics.variance(timings),
"tokens_per_second": 50 / statistics.median(timings),
# Grotere modellen hebben over het algemeen minder tokens/seconde
}Toepassing in de praktijk
Aanvalsstrategieën kiezen op basis van de model-ID
Zodra het model is geïdentificeerd, kan het red team de meest effectieve aanvalsaanpak kiezen:
ATTACK_RECOMMENDATIONS = {
"OpenAI GPT": {
"effective_techniques": [
"multi-turn escalation",
"role-play framing",
"few-shot jailbreaking"
],
"known_weaknesses": [
"instruction hierarchy bypass via developer messages",
"function calling manipulation"
],
"less_effective": [
"direct instruction override (well-defended)",
"GCG suffixes (actively filtered)"
]
},
"Anthropic Claude": {
"effective_techniques": [
"many-shot jailbreaking",
"role-play with detailed personas",
"progressive topic shifting"
],
"known_weaknesses": [
"long-context attention patterns",
"system prompt extraction via reasoning"
],
"less_effective": [
"simple DAN-style prompts",
"basic instruction override"
]
},
# ... aanvullende modelfamilies
}Gerelateerde onderwerpen
- Target Profiling — Bredere methodiek voor het beoordelen van een doelwit
- API Enumeration — API-capaciteiten ontdekken
- System Prompt Extraction — De configuratie extraheren na identificatie
Een API antwoordt op 'What model are you?' met 'I'm a helpful AI assistant.' Hij gebruikt veel markdown-opmaak, geeft gedetailleerde wiskundige oplossingen stap voor stap, en weigert verzoeken met een verwijzing naar 'our usage policy.' Welke modelfamilie is het meest waarschijnlijk?
Referenties
- Ippolito et al., "Reverse-Engineering Decoding Strategies Given Blackbox Access to a Language Generation System" (2020)
- Shen et al., "Identifying LLMs Behind API Endpoints" (2024)
- Carlini et al., "Stealing Part of a Production Language Model" (2024)