Skip to content

Instantly share code, notes, and snippets.

@jossemarGT
Last active May 2, 2018 05:37
Show Gist options
  • Select an option

  • Save jossemarGT/8b4df49c8be1806c6490f28de344649a to your computer and use it in GitHub Desktop.

Select an option

Save jossemarGT/8b4df49c8be1806c6490f28de344649a to your computer and use it in GitHub Desktop.
Generate CMS login session cookie
@Grab(group='net.razorvine', module='pyrolite', version='4.20')
@Grab(group='com.jossemargt', module='cookie-twist', version='0.3.1')
// HMAC SHA256 sign
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Formatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
// Time
import java.time.Instant
// Pickler v0 (Tailor made)
import net.razorvine.pickle.Opcodes;
import java.io.ByteArrayOutputStream;
// Tornado Secure Cookie port
import java.nio.charset.StandardCharsets;
import javax.servlet.http.Cookie
import com.jossemargt.cookietwist.tornado.transform.impl.V2TornadoCookieCodec;
String HMAC_SHA256_ALGORITHM = 'HmacSHA256'
final contestSlug = 'con_test'
final cmsURL = 'http://192.168.7.10'
final cookieSecret = '8e045a51e4b102ea803c06f92841a1fb'
final b64CookieSecret = utf8Bytes(cookieSecret).encodeBase64().toString()
String toHexString(byte[] bytes) {
Formatter formatter = new Formatter();
for (byte b : bytes) {
formatter.format("%02x", b);
}
return formatter.toString();
}
String calculateHMACSHA256(byte[] key, byte[] data) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec signingKey = new SecretKeySpec(key, 'HmacSHA256');
Mac mac = Mac.getInstance('HmacSHA256');
mac.init(signingKey);
return toHexString(mac.doFinal(data));
}
byte[] utf8Bytes (def data) {
return data.getBytes(StandardCharsets.UTF_8)
}
byte[] pickle0dumpsCMS(String username, String password, String timestamp) {
ByteArrayOutputStream bos=new ByteArrayOutputStream();
def newLine = utf8Bytes('\n')
bos.write(Opcodes.MARK); bos.write(Opcodes.UNICODE); bos.write(utf8Bytes(username)); bos.write(newLine)
bos.write(Opcodes.PUT); bos.write(utf8Bytes('0')); bos.write(newLine)
bos.write(Opcodes.UNICODE); bos.write(utf8Bytes("plaintext:${password}")); bos.write(newLine)
bos.write(Opcodes.PUT); bos.write(utf8Bytes('1')); bos.write(newLine)
bos.write(Opcodes.FLOAT); bos.write(utf8Bytes(timestamp)); bos.write(newLine)
bos.write(Opcodes.TUPLE); bos.write(Opcodes.PUT); bos.write(utf8Bytes('2')); bos.write(newLine)
bos.write(Opcodes.STOP);
bos.flush()
return bos.toByteArray()
}
String tornadoSignedValueField( token ) {
Formatter formatter = new Formatter();
formatter.format("%d:%s", token.size(), token);
return formatter.toString();
}
String tornadoCreateSignedValue(secret, name, value, timestamp) {
def toSign = [ '0', timestamp, name, value ].collect{ tornadoSignedValueField(it) }
toSign.add(0, '2')
toSign.add('')
def toSignStr = toSign.join('|')
def signature = calculateHMACSHA256(utf8Bytes(secret), utf8Bytes(toSignStr))
return toSignStr + signature
}
def epochNow = Instant.now().getEpochSecond()
def pickledHashBytes = pickle0dumpsCMS('u1', 'p1', epochNow.toString())
def pickledHashStr = new String(pickledHashBytes, StandardCharsets.UTF_8);
def cookieValue = tornadoCreateSignedValue(b64CookieSecret, 'con_test_login', pickledHashBytes.encodeBase64().toString(), epochNow.toString())
// -------------- Using Tornado secure cookies port
def cookieCoder = V2TornadoCookieCodec.builder().withTimestamp(epochNow).withSecretKey(b64CookieSecret).build();
def signedCookie = cookieCoder.encodeCookie(new Cookie ("${contestSlug}_login" , pickledHashStr ))
// Manually Generated cookie value
println "---" * 5
println ">>> Cookie generated within this script:"
println "${contestSlug}_login=\"${cookieValue}\""
// Doing the same request as the tampered one with the generated cookie value
println ">>> Was it a succesful login? " + "${cmsURL}/${contestSlug}".
toURL().
getText(requestProperties: ['Cookie': "${contestSlug}_login=\"${cookieValue}\"".toString()]).
contains("Logged in as ")
// cookie-twist generated value
println "---" * 5
println ">>> Cookie generated with cookie-twist library"
println "$signedCookie.name=\"$signedCookie.value\""
println ">>> Was it a succesful login? " + "${cmsURL}/${contestSlug}".
toURL().
getText(requestProperties: ['Cookie': "${signedCookie.name}=\"${signedCookie.value}\"".toString()]).
contains("Logged in as ")
println "---" * 5
/**
* Console output:
* $ groovy cms_gerate_login.groovy
* ---------------
* >>> Cookie generated within this script:
* con_test_login="2|1:0|10:1525237414|14:con_test_login|56:KFZ1MQpwMApWcGxhaW50ZXh0OnAxCnAxCkYxNTI1MjM3NDE0CnRwMgou|0be2f709c31a73f28eed9a5f6648ea58ba4e75419b533a82f830c7cc878664c4"
* >>> Was it a succesful login? true
* ---------------
* >>> Cookie generated with cookie-twist library
* con_test_login="2|1:0|10:1525237414|14:con_test_login|56:KFZ1MQpwMApWcGxhaW50ZXh0OnAxCnAxCkYxNTI1MjM3NDE0CnRwMgou|0be2f709c31a73f28eed9a5f6648ea58ba4e75419b533a82f830c7cc878664c4"
* >>> Was it a succesful login? true
* ---------------
*/
@jossemarGT

jossemarGT commented May 2, 2018

Copy link
Copy Markdown
Author

This script was tested against CMS revision f7ebce619b886cbdd4620123889860a908f4ca65 (prior to its 1.3.0 release).

Bear in mind that the latest releases don't base64 encode the cookie_secret anymore, it seems the application transform the secret into its hex string representation using binascii.b2a_hex

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