Skip to content

Instantly share code, notes, and snippets.

@lkraider
Created June 14, 2020 21:25
Show Gist options
  • Save lkraider/9530798a695586fc1580d0728966f6f0 to your computer and use it in GitHub Desktop.
Save lkraider/9530798a695586fc1580d0728966f6f0 to your computer and use it in GitHub Desktop.
X-OVH-SPAMCAUSE decoder
def decode(msg):
text = []
for i in range(0, len(msg), 2):
text.append(unrot(msg[i: i + 2]))
return str.join('', text)
def unrot(pair, key=ord('x')):
offset = 0
for c in 'cdefgh':
if c in pair:
offset = (ord('g') - ord(c)) * 16
break
return chr(sum(ord(c) for c in pair) - key - offset)
if __name__ == '__main__':
import sys
print(decode(sys.argv[1]))
@plegrand1
Copy link

Just to know, is it normal that the result is truncated
Thanks again

@DoubleYouEl
Copy link

Can you provide an example? In principle, the entire spamcause string is parsed and decoded.

@arbiyassine17
Copy link

is there any updte for this vad decoder? it cannot decrypt this
X-Spamcause: dmFkZTEXAf7aJW+CObm3ConPoxO2B57jkK1eWV41nKjpNyF5O9Fedv3pf9sOxvbr3kehXrA2ml2Wx4tdJFDANYeUI5UPAa+44GGqT5Wk/CegS9N1LE74n0mMi0pnk636eEOiXt7iakkXGOEDL7R6udwHSUkAhrLEWFyU1h87u20MpBmDccfMEjsbWTzuXngth8oBItZl1gW63vQ/l9cLp8ZsSWwnwF4PxdZmUNBIv0dSar9EXKjr6UqJ3Bo0cUCoY+1n1NC1fpwJn3OwEJr3n/jnYTdPTMQXH5QNZ7oI1DXtk9tMtAgNHDxMWa6rZP6kTKBIujzEHieM7p+SBn4x8h31yAPOQBDT7JZZWwk9MKMDw8EoWb+AEE+aVPg03yrV2Ml4Nb1rqFd1FnIHV9ushfYIAdig9tnS7WoK/trJLmlF9UUPzpfKNHpxI/Fco+KJBAZ08YEDfcXxTutCaq9WnMQKNGPACAtP91Mv4lAj9h08OHgrzJbpUSzRWT6MM76wn91NeSo+oJF8gMNkgLS1EkAhQK6tzDFJ+Sdk7CA5z0RyxdPNEJ0O7wEaZ7unxYPMw+cDH+D63nqEJ1mmQTgtj/5GUFZyWoVPxExo4tMETsc8v3jg3GW5V/INZgGUBPoU5VsdFR4peXGmqrb/CRyaMpzqm9IKxgS1Fs88z1utyPjVWILVtg

@DoubleYouEl
Copy link

is there any updte for this vad decoder? it cannot decrypt this X-Spamcause: dmFkZTEXAf7aJW+CObm3ConPoxO2B57jkK1eWV41nKjpNyF5O9Fedv3pf9sOxvbr3kehXrA2ml2Wx4tdJFDANYeUI5UPAa+44GGqT5Wk/CegS9N1LE74n0mMi0pnk636eEOiXt7iakkXGOEDL7R6udwHSUkAhrLEWFyU1h87u20MpBmDccfMEjsbWTzuXngth8oBItZl1gW63vQ/l9cLp8ZsSWwnwF4PxdZmUNBIv0dSar9EXKjr6UqJ3Bo0cUCoY+1n1NC1fpwJn3OwEJr3n/jnYTdPTMQXH5QNZ7oI1DXtk9tMtAgNHDxMWa6rZP6kTKBIujzEHieM7p+SBn4x8h31yAPOQBDT7JZZWwk9MKMDw8EoWb+AEE+aVPg03yrV2Ml4Nb1rqFd1FnIHV9ushfYIAdig9tnS7WoK/trJLmlF9UUPzpfKNHpxI/Fco+KJBAZ08YEDfcXxTutCaq9WnMQKNGPACAtP91Mv4lAj9h08OHgrzJbpUSzRWT6MM76wn91NeSo+oJF8gMNkgLS1EkAhQK6tzDFJ+Sdk7CA5z0RyxdPNEJ0O7wEaZ7unxYPMw+cDH+D63nqEJ1mmQTgtj/5GUFZyWoVPxExo4tMETsc8v3jg3GW5V/INZgGUBPoU5VsdFR4peXGmqrb/CRyaMpzqm9IKxgS1Fs88z1utyPjVWILVtg

This cannot be a correct X-Spamcause string, I'm afraid...

@arbiyassine17
Copy link

no bro it is correct here is the full header

Authentication-Results:mail94c7.megamailservers.com; spf=tempfail smtp.mailfrom=localhost.localdomain
Content-Type:text/html
Date:Wed, 7 May 2025 06:59:20 +0000 (UTC)
Dmarc-Filter:OpenDMARC Filter v1.4.2 mail94c7.megamailservers.com 5476xLl43206121
From:[email protected]
Message-ID:20250507065921.1C1B847E40B@localhost
Mime-Version:1.0
Received:by localhost (Postfix, from userid 0) id 1C1B847E40B; Wed, 7 May 2025 06:59:21 +0000 (UTC)
Return-Path:[email protected]
Subject:SPAM fedex Delivery Waiting
To:[email protected]
X-Envelope-From:[email protected]
X-Origin-Asn:396982
X-Origin-Country:US
X-Rspamd-Result:default: False [6.30 / 6.00]; HFILTER_HELO_5(3.00)[localhost]; DMARC_POLICY_REJECT(2.00)[fedex.com : No valid SPF, No valid DKIM,reject]; MID_RHS_NOT_FQDN(0.50)[]; FORGED_SENDER(0.30)[[email protected],[email protected]]; MIME_HTML_ONLY(0.20)[]; ONCE_RECEIVED(0.20)[]; RCVD_NO_TLS_LAST(0.10)[]; R_DKIM_NA(0.00)[]; MIME_TRACE(0.00)[0:~]; RCVD_COUNT_ONE(0.00)[1]; MISSING_XM_UA(0.00)[]; FROM_NEQ_ENVFROM(0.00)[[email protected],[email protected]]; TO_MATCH_ENVRCPT_ALL(0.00)[]; FROM_NO_DN(0.00)[]; RCPT_COUNT_ONE(0.00)[1]; R_SPF_DNSFAIL(0.00)[temporary DNS error]; ASN(0.00)[asn:396982, ipnet:34.139.192.0/20, country:US]; TO_DN_NONE(0.00)[]; NEURAL_SPAM(0.00)[0.836]; ARC_NA(0.00)[]
X-Rspamd-Status:Yes, score=6.30
X-Spam:Yes
X-Spam-Factor:VADE
X-Spam-Flag:YES
X-Vade-Spamcause:dmFkZTF74xMy5IslKlQPpK1gvXw5/PTzaumShCvGY+Z8PpTElnP2aFtqqcuFX6ZDTCkC36le50IslWryQpehrW79UO5ANoj6u2AsT5lURJfSGXsNsJ0lkIT32Jn8x63CUQBTMQ5GKnSGt34wQLcz9Iw9Kjv581O22AEbmjD9f0a9g6TfxsvCN3NSzhHsTyxuEX9shIaU/lr8QTxpuQ84zb9QPrqD35NGRjrZAcpITiHmsgqpn8tlSLyiv0mRFltixK6H3bN1u61RmRKkaUK8uYjnGjVOapKsoCtt2n5Q/JTo1zlGcrxdlxhEYSXgVCio5FlkmJLbMhgIMa5GK/fZESAcqEv+cS6Lb1JFqQtZyunHPQzzBKetAhJyVpvPoZP4ja0UMopH4RUvebNS5BuIqI8RQkIyU4BkgusrQEkoF2Opo3ddLmVo54AqRkRi0ougPmiKJyDStDoQQroWvDjTAGdHu30reJoUlY0K+j2zQ7TDi6ZaEdvWddYkCAfwdODtzSfTBYnb18SpRRKBF/fROnvZUI3Fbp2BT45j4NFi5FQtWlC1izWr1eywwX/wa3jky8rdqEJVRd/Mes1IZ0PX9VVttk37fPX0nmnVOf69Dmb0GUI3Z1E/5K9ClhlMpsm7jr0jASbRtEKIFw+A00dm14N9+KJg4gusfE/LCzFBRBKYFK/Jdw
X-Vade-Spamscore:500
X-Vade-Spamstate:spam:high
X-Whl:LR

@lkraider
Copy link
Author

lkraider commented May 8, 2025

Looks like a base64 binary content, running base64 decode returns and ASCII prefix: vade1{…} confirming the version marker.

Sample code:

import base64

# The full Base64-encoded X-Vade-Spamcause header value
spamcause_b64 = (
    "dmFkZTF74xMy5IslKlQPpK1gvXw5/PTzaumShCvGY+Z8PpTElnP2aFtqqcuFX6ZDTCkC36le50IslWryQpehrW79UO5ANoj6u2AsT5l"
    "URJfSGXsNsJ0lkIT32Jn8x63CUQBTMQ5GKnSGt34wQLcz9Iw9Kjv581O22AEbmjD9f0a9g6TfxsvCN3NSzhHsTyxuEX9shIaU/lr8Q"
    "TxpuQ84zb9QPrqD35NGRjrZAcpITiHmsgqpn8tlSLyiv0mRFltixK6H3bN1u61RmRKkaUK8uYjnGjVOapKsoCtt2n5Q/JTo1zlGcrx"
    "dlxhEYSXgVCio5FlkmJLbMhgIMa5GK/fZESAcqEv+cS6Lb1JFqQtZyunHPQzzBKetAhJyVpvPoZP4ja0UMopH4RUvebNS5BuIqI8R"
    "QkIyU4BkgusrQEkoF2Opo3ddLmVo54AqRkRi0ougPmiKJyDStDoQQroWvDjTAGdHu30reJoUlY0K+j2zQ7TDi6ZaEdvWddYkCAfwd"
    "ODtzSfTBYnb18SpRRKBF/fROnvZUI3Fbp2BT45j4NFi5FQtWlC1izWr1eywwX/wa3jky8rdqEJVRd/Mes1IZ0PX9VVttk37fPX0n"
    "mnVOf69Dmb0GUI3Z1E/5K9ClhlMpsm7jr0jASbRtEKIFw+A00dm14N9+KJg4gusfE/LCzFBRBKYFK/Jdw"
)

# Ensure correct padding
spamcause_b64 += "=" * ((4 - len(spamcause_b64) % 4) % 4)

# Decode Base64 to raw bytes
decoded = base64.b64decode(spamcause_b64)

# Build mixed ASCII/hex representation
output = []
for b in decoded:
    if 32 <= b <= 126:  # printable ASCII range
        output.append(chr(b))
    else:
        output.append(f"\\x{b:02x}")

mixed_repr = "".join(output)

# Print the result
print(mixed_repr)

STDOUT/STDERR

vade1{\xe3\x132\xe4\x8b%*T\x0f\xa4\xad`\xbd|9\xfc\xf4\xf3j\xe9\x92\x84+\xc6c\xe6|>\x94\xc4\x96s\xf6h[j\xa9\xcb\x85_\xa6CL)\x02\xdf\xa9^\xe7B,\x95j\xf2B\x97\xa1\xadn\xfdP\xee@6\x88\xfa\xbb`,O\x99TD\x97\xd2\x19{\x0d\xb0\x9d%\x90\x84\xf7\xd8\x99\xfc\xc7\xad\xc2Q\x00S1\x0eF*t\x86\xb7~0@\xb73\xf4\x8c=*;\xf9\xf3S\xb6\xd8\x01\x1b\x9a0\xfd\x7fF\xbd\x83\xa4\xdf\xc6\xcb\xc27sR\xce\x11\xecO,n\x11\x7fl\x84\x86\x94\xfeZ\xfcA<i\xb9\x0f8\xcd\xbfP>\xba\x83\xdf\x93FF:\xd9\x01\xcaHN!\xe6\xb2\x0a\xa9\x9f\xcbeH\xbc\xa2\xbfI\x91\x16[b\xc4\xae\x87\xdd\xb3u\xbb\xadQ\x99\x12\xa4iB\xbc\xb9\x88\xe7\x1a5Nj\x92\xac\xa0+m\xda~P\xfc\x94\xe8\xd79Fr\xbc]\x97\x18Da%\xe0T(\xa8\xe4Yd\x98\x92\xdb2\x18\x081\xaeF+\xf7\xd9\x11 \x1c\xa8K\xfeq.\x8boRE\xa9\x0bY\xca\xe9\xc7=\x0c\xf3\x04\xa7\xad\x02\x12rV\x9b\xcf\xa1\x93\xf8\x8d\xad\x142\x8aG\xe1\x15/y\xb3R\xe4\x1b\x88\xa8\x8f\x11BB2S\x80d\x82\xeb+@I(\x17c\xa9\xa3w].eh\xe7\x80*FDb\xd2\x8b\xa0>h\x8a' \xd2\xb4:\x10B\xba\x16\xbc8\xd3\x00gG\xbb}+x\x9a\x14\x95\x8d\x0a\xfa=\xb3C\xb4\xc3\x8b\xa6Z\x11\xdb\xd6u\xd6$\x08\x07\xf0t\xe0\xed\xcd'\xd3\x05\x89\xdb\xd7\xc4\xa9E\x12\x81\x17\xf7\xd1:{\xd9P\x8d\xc5n\x9d\x81O\x8ec\xe0\xd1b\xe4T-ZP\xb5\x8b5\xab\xd5\xec\xb0\xc1\x7f\xf0kx\xe4\xcb\xca\xdd\xa8BUE\xdf\xccz\xcdHgC\xd7\xf5Um\xb6M\xfb|\xf5\xf4\x9ei\xd59\xfe\xbd\x0ef\xf4\x19B7gQ?\xe4\xafB\x96\x19L\xa6\xc9\xbb\x8e\xbd#\x01&\xd1\xb4B\x88\x17\x0f\x80\xd3Gf\xd7\x83}\xf8\xa2`\xe2\x0b\xac|O\xcb\x0b1AD\x12\x98\x14\xaf\xc9w

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment