shadow1ng/fscan · error
i18n.GetText("ms17010_ciphertext_too_short")
Error message
i18n.GetText("ms17010_ciphertext_too_short") What it means
aesDecrypt rejects ciphertext whose decoded length is less than aes.BlockSize (16 bytes) with "ms17010_ciphertext_too_short". CBC mode requires at least one full block, so any shorter decoded blob cannot be a valid AES-CBC ciphertext.
Source
Thrown at plugins/services/ms17010.go:184
}
// 以下是完整的原始MS17010检测和利用代码,保持不变
// AES解密函数 (从legacy/Base.go复制)
func aesDecrypt(crypted string, key string) (string, error) {
cryptedBytes, err := base64.StdEncoding.DecodeString(crypted)
if err != nil {
return "", fmt.Errorf("%s: %w", i18n.GetText("ms17010_base64_decode_failed"), err)
}
keyBytes := []byte(key)
block, err := aes.NewCipher(keyBytes)
if err != nil {
return "", fmt.Errorf("%s: %w", i18n.GetText("ms17010_aes_cipher_failed"), err)
}
if len(cryptedBytes) < aes.BlockSize {
return "", fmt.Errorf("%s", i18n.GetText("ms17010_ciphertext_too_short"))
}
mode := cipher.NewCBCDecrypter(block, keyBytes[:aes.BlockSize])
mode.CryptBlocks(cryptedBytes, cryptedBytes)
// 移除PKCS7填充
padding := int(cryptedBytes[len(cryptedBytes)-1])
if padding > len(cryptedBytes) || padding > aes.BlockSize {
return "", fmt.Errorf("%s", i18n.GetText("ms17010_invalid_padding"))
}
for i := len(cryptedBytes) - padding; i < len(cryptedBytes); i++ {
if cryptedBytes[i] != byte(padding) {
return "", fmt.Errorf("%s", i18n.GetText("ms17010_padding_check_failed"))
}
}
return string(cryptedBytes[:len(cryptedBytes)-padding]), nilView on GitHub (pinned to 95cc12e753)
Solutions
- Base64-decode and assert len >= 16 bytes before calling aesDecrypt.
- Verify the payload source actually emits AES-CBC ciphertext (multiple of 16 bytes, IV prepended or keyed separately).
- Check the payload wasn't truncated in storage/transport (compare length with the producer's byte count).
- If your scheme prepends a 16-byte IV, remember the minimum valid total is 32 bytes (IV + one block).
Example fix
// before
plain, err := aesDecrypt(tok, key)
// after: pre-check decoded size
raw, _ := base64.StdEncoding.DecodeString(tok)
if len(raw) < aes.BlockSize || len(raw)%aes.BlockSize != 0 {
return fmt.Errorf("ciphertext must be >=16 bytes and block-aligned, got %d", len(raw))
}
plain, err := aesDecrypt(tok, key) Defensive patterns
Strategy: validation
Validate before calling
raw, err := base64.StdEncoding.DecodeString(payload)
if err != nil { return err }
if len(raw) < aes.BlockSize || len(raw)%aes.BlockSize != 0 {
return fmt.Errorf("ciphertext must be >=16 bytes and 16-byte aligned, got %d", len(raw))
} Try / catch
plain, err := aesDecrypt(payload, key)
if err != nil && strings.Contains(err.Error(), "too_short") {
return fmt.Errorf("truncated or non-CBC payload")
} Prevention
- Verify payload lengths against the producer before decrypting
- Remember the minimum is IV(16) + one block(16) if IV is embedded
- Use checksums on stored ciphertext to catch truncation
When it happens
Trigger: aesDecrypt receives a crypted string that base64-decodes to 0–15 bytes: empty string, truncated payload, or data that was never AES-CBC encrypted (e.g. plaintext, checksum, or IV-only).
Common situations: Copy/paste truncation of long payloads, feeding the IV alone instead of IV||ciphertext, or decrypting a field produced by a different scheme (GCM tag, hex blob).
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ms17010_invalid_padding
- i18n.GetText("ms17010_base64_decode_failed"): %w
- i18n.GetText("ms17010_aes_cipher_failed"): %w
- ms17010_padding_check_failed
- i18n.GetText("ms17010_not_vulnerable")
AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06).
Data as JSON: /api/errors/9495089900659145.
Report an issue: GitHub.