Last active
December 5, 2022 16:09
-
-
Save TrebledJ/ba53a8c720de910e0bdc55892171f76e to your computer and use it in GitHub Desktop.
Solve scripts for HKCERT 2022 C++harming Website. charm.h and .c are taken from https://github.com/jedisct1/charm. Writeup: https://trebledj.github.io/posts/hkcert-2022-cpp-harming-website/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#ifdef __SSSE3__ | |
#include <x86intrin.h> | |
#endif | |
#if defined(__ARM_NEON) || defined(__aarch64__) | |
#include <arm_neon.h> | |
#endif | |
#ifdef __linux__ | |
#ifndef _GNU_SOURCE | |
#define _GNU_SOURCE | |
#endif | |
#include <sys/syscall.h> | |
#include <unistd.h> | |
#endif | |
#include "charm.h" | |
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ | |
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ | |
#define NATIVE_BIG_ENDIAN | |
#endif | |
#ifndef NATIVE_BIG_ENDIAN | |
#ifndef NATIVE_LITTLE_ENDIAN | |
#define NATIVE_LITTLE_ENDIAN | |
#endif | |
#endif | |
#ifndef XOODOO_ROUNDS | |
#define XOODOO_ROUNDS 12 | |
#endif | |
static inline void mem_cpy(unsigned char *dst, const unsigned char *src, size_t n) | |
{ | |
size_t i; | |
for (i = 0; i < n; i++) { | |
dst[i] = src[i]; | |
} | |
} | |
static const uint32_t RK[12] = { 0x058, 0x038, 0x3c0, 0x0d0, 0x120, 0x014, | |
0x060, 0x02c, 0x380, 0x0f0, 0x1a0, 0x012 }; | |
#ifdef __SSSE3__ | |
#define ROL32in128(x, b) _mm_or_si128(_mm_slli_epi32((x), (b)), _mm_srli_epi32((x), 32 - (b))) | |
static void permute(uint32_t st[12]) | |
{ | |
const __m128i rhoEast2 = _mm_set_epi32(0x06050407, 0x02010003, 0x0e0d0c0f, 0x0a09080b); | |
__m128i a, b, c, p, e; | |
int r; | |
a = _mm_loadu_si128((const __m128i *) (const void *) &st[0]); | |
b = _mm_loadu_si128((const __m128i *) (const void *) &st[4]); | |
c = _mm_loadu_si128((const __m128i *) (const void *) &st[8]); | |
for (r = 0; r < XOODOO_ROUNDS; r++) { | |
p = _mm_shuffle_epi32(_mm_xor_si128(_mm_xor_si128(a, b), c), 0x93); | |
e = ROL32in128(p, 5); | |
p = ROL32in128(p, 14); | |
e = _mm_xor_si128(e, p); | |
a = _mm_xor_si128(a, e); | |
b = _mm_xor_si128(b, e); | |
c = _mm_xor_si128(c, e); | |
b = _mm_shuffle_epi32(b, 0x93); | |
c = ROL32in128(c, 11); | |
a = _mm_xor_si128(a, _mm_set_epi32(0, 0, 0, RK[r])); | |
a = _mm_xor_si128(a, _mm_andnot_si128(b, c)); | |
b = _mm_xor_si128(b, _mm_andnot_si128(c, a)); | |
c = _mm_xor_si128(c, _mm_andnot_si128(a, b)); | |
b = ROL32in128(b, 1); | |
c = _mm_shuffle_epi8(c, rhoEast2); | |
} | |
_mm_storeu_si128((__m128i *) (void *) &st[0], a); | |
_mm_storeu_si128((__m128i *) (void *) &st[4], b); | |
_mm_storeu_si128((__m128i *) (void *) &st[8], c); | |
} | |
#elif defined(__ARM_NEON) || defined(__aarch64__) | |
#define ROL32in128(x, b) vsriq_n_u32(vshlq_n_u32((x), (b)), (x), 32 - (b)) | |
static void permute(uint32_t st[12]) | |
{ | |
uint32x4_t a, b, c, d, e, f; | |
int r; | |
a = vld1q_u32((const uint32_t *) (const void *) &st[0]); | |
b = vld1q_u32((const uint32_t *) (const void *) &st[4]); | |
c = vld1q_u32((const uint32_t *) (const void *) &st[8]); | |
for (r = 0; r < XOODOO_ROUNDS; r++) { | |
d = veorq_u32(veorq_u32(a, b), c); | |
d = vextq_u32(d, d, 3); | |
e = ROL32in128(d, 5); | |
f = ROL32in128(d, 14); | |
e = veorq_u32(e, f); | |
a = veorq_u32(a, e); | |
b = veorq_u32(b, e); | |
f = veorq_u32(c, e); | |
c = ROL32in128(f, 11); | |
b = vextq_u32(b, b, 3); | |
a = veorq_u32(a, vsetq_lane_u32(RK[r], vmovq_n_u32(0), 0)); | |
e = vbicq_u32(c, b); | |
d = vbicq_u32(a, c); | |
f = vbicq_u32(b, a); | |
a = veorq_u32(a, e); | |
d = veorq_u32(b, d); | |
c = veorq_u32(c, f); | |
f = vextq_u32(c, c, 2); | |
b = ROL32in128(d, 1); | |
c = ROL32in128(f, 8); | |
} | |
vst1q_u32((uint32_t *) (void *) &st[0], a); | |
vst1q_u32((uint32_t *) (void *) &st[4], b); | |
vst1q_u32((uint32_t *) (void *) &st[8], c); | |
} | |
#else | |
#define ROTR32(x, b) (uint32_t)(((x) >> (b)) | ((x) << (32 - (b)))) | |
#define SWAP32(s, u, v) \ | |
do { \ | |
t = (s)[u]; \ | |
(s)[u] = (s)[v], (s)[v] = t; \ | |
} while (0) | |
static void permute(uint32_t st[12]) | |
{ | |
uint32_t e[4], a, b, c, t, r, i; | |
for (r = 0; r < XOODOO_ROUNDS; r++) { | |
for (i = 0; i < 4; i++) { | |
e[i] = ROTR32(st[i] ^ st[i + 4] ^ st[i + 8], 18); | |
e[i] ^= ROTR32(e[i], 9); | |
} | |
for (i = 0; i < 12; i++) { | |
st[i] ^= e[(i - 1) & 3]; | |
} | |
SWAP32(st, 7, 4); | |
SWAP32(st, 7, 5); | |
SWAP32(st, 7, 6); | |
st[0] ^= RK[r]; | |
for (i = 0; i < 4; i++) { | |
a = st[i]; | |
b = st[i + 4]; | |
c = ROTR32(st[i + 8], 21); | |
st[i + 8] = ROTR32((b & ~a) ^ c, 24); | |
st[i + 4] = ROTR32((a & ~c) ^ b, 31); | |
st[i] ^= c & ~b; | |
} | |
SWAP32(st, 8, 10); | |
SWAP32(st, 9, 11); | |
} | |
} | |
#endif | |
static inline void endian_swap_rate(uint32_t st[12]) | |
{ | |
(void) st; | |
#ifdef NATIVE_BIG_ENDIAN | |
size_t i; | |
for (i = 0; i < 4; i++) { | |
st[i] = __builtin_bswap32(st[i]); | |
} | |
#endif | |
} | |
static inline void endian_swap_all(uint32_t st[12]) | |
{ | |
(void) st; | |
#ifdef NATIVE_BIG_ENDIAN | |
size_t i; | |
for (i = 0; i < 12; i++) { | |
st[i] = __builtin_bswap32(st[i]); | |
} | |
#endif | |
} | |
static inline void xor128(void *out, const void *in) | |
{ | |
#ifdef __SSSE3__ | |
_mm_storeu_si128((__m128i *) out, | |
_mm_xor_si128(_mm_loadu_si128((const __m128i *) out), | |
_mm_loadu_si128((const __m128i *) in))); | |
#else | |
unsigned char * out_ = (unsigned char *) out; | |
const unsigned char *in_ = (const unsigned char *) in; | |
size_t i; | |
for (i = 0; i < 16; i++) { | |
out_[i] ^= in_[i]; | |
} | |
#endif | |
} | |
static inline int equals(const unsigned char a[16], const unsigned char b[16], size_t len) | |
{ | |
unsigned char d = 0; | |
size_t i; | |
for (i = 0; i < len; i++) { | |
d |= a[i] ^ b[i]; | |
} | |
return 1 & ((d - 1) >> 8); | |
} | |
static inline void squeeze_permute(uint32_t st[12], unsigned char dst[16]) | |
{ | |
endian_swap_rate(st); | |
memcpy(dst, st, 16); | |
endian_swap_rate(st); | |
permute(st); | |
} | |
void uc_state_init(uint32_t st[12], const unsigned char key[32], const unsigned char iv[16]) | |
{ | |
if (iv != NULL) { | |
memcpy(&st[0], iv, 16); | |
} else { | |
memset(&st[0], 0, 16); | |
} | |
memcpy(&st[4], key, 32); | |
endian_swap_all(st); | |
permute(st); | |
} | |
void uc_encrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, unsigned char tag[16]) | |
{ | |
unsigned char squeezed[16]; | |
unsigned char padded[16 + 1]; | |
size_t off = 0; | |
size_t leftover; | |
if (msg_len > 16) { | |
for (; off < msg_len - 16; off += 16) { | |
endian_swap_rate(st); | |
memcpy(squeezed, st, 16); | |
xor128(st, &msg[off]); | |
endian_swap_rate(st); | |
xor128(&msg[off], squeezed); | |
permute(st); | |
} | |
} | |
leftover = msg_len - off; | |
memset(padded, 0, 16); | |
mem_cpy(padded, &msg[off], leftover); | |
padded[leftover] = 0x80; | |
endian_swap_rate(st); | |
memcpy(squeezed, st, 16); | |
xor128(st, padded); | |
endian_swap_rate(st); | |
st[11] ^= (1UL << 24 | (uint32_t) leftover >> 4 << 25 | 1UL << 26); | |
xor128(padded, squeezed); | |
mem_cpy(&msg[off], padded, leftover); | |
permute(st); | |
squeeze_permute(st, tag); | |
} | |
int uc_decrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, | |
const unsigned char *expected_tag, size_t expected_tag_len) | |
{ | |
unsigned char tag[16]; | |
unsigned char squeezed[16]; | |
unsigned char padded[16 + 1]; | |
size_t off = 0; | |
size_t leftover; | |
if (msg_len > 16) { | |
for (; off < msg_len - 16; off += 16) { | |
endian_swap_rate(st); | |
memcpy(squeezed, st, 16); | |
xor128(&msg[off], squeezed); | |
xor128(st, &msg[off]); | |
endian_swap_rate(st); | |
permute(st); | |
} | |
} | |
leftover = msg_len - off; | |
memset(padded, 0, 16); | |
mem_cpy(padded, &msg[off], leftover); | |
endian_swap_rate(st); | |
memset(squeezed, 0, 16); | |
mem_cpy(squeezed, (const unsigned char *) (const void *) st, leftover); | |
xor128(&padded, squeezed); | |
padded[leftover] = 0x80; | |
xor128(st, padded); | |
endian_swap_rate(st); | |
st[11] ^= (1UL << 24 | (uint32_t) leftover >> 4 << 25 | 1UL << 26); | |
mem_cpy(&msg[off], padded, leftover); | |
permute(st); | |
squeeze_permute(st, tag); | |
if (equals(expected_tag, tag, expected_tag_len) == 0) { | |
memset(msg, 0, msg_len); | |
return -1; | |
} | |
return 0; | |
} | |
void uc_hash(uint32_t st[12], unsigned char h[32], const unsigned char *msg, size_t len) | |
{ | |
unsigned char padded[16 + 1]; | |
size_t off = 0; | |
size_t leftover; | |
if (len > 16) { | |
for (; off < len - 16; off += 16) { | |
endian_swap_rate(st); | |
xor128(st, &msg[off]); | |
endian_swap_rate(st); | |
permute(st); | |
} | |
} | |
leftover = len - off; | |
memset(padded, 0, 16); | |
mem_cpy(padded, &msg[off], leftover); | |
padded[leftover] = 0x80; | |
endian_swap_rate(st); | |
xor128(st, padded); | |
endian_swap_rate(st); | |
st[11] ^= (1UL << 24 | (uint32_t) leftover >> 4 << 25); | |
permute(st); | |
squeeze_permute(st, &h[0]); | |
squeeze_permute(st, &h[16]); | |
} | |
void uc_memzero(void *buf, size_t len) | |
{ | |
volatile unsigned char *volatile buf_ = (volatile unsigned char *volatile) buf; | |
size_t i = (size_t) 0U; | |
while (i < len) { | |
buf_[i++] = 0U; | |
} | |
} | |
void uc_randombytes_buf(void *buf, size_t len) | |
{ | |
#ifdef __linux__ | |
if ((size_t) syscall(SYS_getrandom, buf, (int) len, 0) != len) { | |
abort(); | |
} | |
#else | |
arc4random_buf(buf, len); | |
#endif | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef charm_H | |
#define charm_H 1 | |
#include <stdint.h> | |
#include <stdlib.h> | |
void uc_state_init(uint32_t st[12], const unsigned char key[32], const unsigned char iv[16]); | |
void uc_encrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, unsigned char tag[16]); | |
int uc_decrypt(uint32_t st[12], unsigned char *msg, size_t msg_len, | |
const unsigned char *expected_tag, size_t expected_tag_len); | |
void uc_hash(uint32_t st[12], unsigned char h[32], const unsigned char *msg, size_t len); | |
void uc_memzero(void *buf, size_t len); | |
void uc_randombytes_buf(void *buf, size_t len); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from base64 import * | |
def decode(s): | |
return ''.join(f'\\x{hex(c)[2:]}' for c in b64decode(s)) | |
print(decode('5Arys5Y8epqG4aSeRcXvf+SKlhNKlQjI22x8ojRv9Deu0EYBstAMMrs+tvnmUV5uFAuXW5kN2jrz4NJm7eh6vG4Mq+w=')) | |
# \xe4\xa\xf2\xb3\x96\x3c\x7a\x9a\x86\xe1\xa4\x9e\x45\xc5\xef\x7f\xe4\x8a\x96\x13\x4a\x95\x8\xc8\xdb\x6c\x7c\xa2\x34\x6f\xf4\x37\xae\xd0\x46\x1\xb2\xd0\xc\x32\xbb\x3e\xb6\xf9\xe6\x51\x5e\x6e\x14\xb\x97\x5b\x99\xd\xda\x3a\xf3\xe0\xd2\x66\xed\xe8\x7a\xbc\x6e\xc\xab\xec | |
print(decode('0FtMYG2IPxj/qFhD/NLGrA==')) | |
# \xd0\x5b\x4c\x60\x6d\x88\x3f\x18\xff\xa8\x58\x43\xfc\xd2\xc6\xac | |
print(decode('4k92GNijCq+ov+7mXOkEHg==')) | |
# \xf2\x9c\x0b\xf1\xc5\x1a\x7e\x65\x75\x80\x23\x6e\x8b\x74\x38\xbf\x59\x39\x8a\x1a\x05\xc6\x43\xfa\x1d\x57\x82\x0a\xb9\xc6\xdc\x50 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// gcc main.c charm.c -o main && ./main | |
#include "charm.h" | |
#include <stdio.h> | |
#include <string.h> | |
int main() { | |
uint32_t st[12] = {}; | |
// Obtained from binary (static_key symbol). | |
unsigned char key[] = "\xf2\x9c\x0b\xf1\xc5\x1a\x7e\x65\x75\x80\x23\x6e\x8b\x74\x38\xbf\x59\x39\x8a\x1a\x05\xc6\x43\xfa\x1d\x57\x82\x0a\xb9\xc6\xdc\x50"; | |
// Obtained by decoding Base64. | |
unsigned char iv[] = "\xe2\x4f\x76\x18\xd8\xa3\xa\xaf\xa8\xbf\xee\xe6\x5c\xe9\x4\x1e"; | |
unsigned char tag[] = "\xd0\x5b\x4c\x60\x6d\x88\x3f\x18\xff\xa8\x58\x43\xfc\xd2\xc6\xac"; | |
unsigned char c[] = "\xe4\xa\xf2\xb3\x96\x3c\x7a\x9a\x86\xe1\xa4\x9e\x45\xc5\xef\x7f\xe4\x8a\x96\x13\x4a\x95\x8\xc8\xdb\x6c\x7c\xa2\x34\x6f\xf4\x37\xae\xd0\x46\x1\xb2\xd0\xc\x32\xbb\x3e\xb6\xf9\xe6\x51\x5e\x6e\x14\xb\x97\x5b\x99\xd\xda\x3a\xf3\xe0\xd2\x66\xed\xe8\x7a\xbc\x6e\xc\xab\xec"; | |
uc_state_init(st, key, iv); | |
size_t len = strlen((char*)c); | |
int res = uc_decrypt(st, c, len, tag, 16); | |
printf("result: %d\n", res); | |
printf("%s\n", c); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment