Skip to content

Instantly share code, notes, and snippets.

@singe
Last active May 29, 2020 19:49
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save singe/a21b7c2e39187a4aa4368204c6790147 to your computer and use it in GitHub Desktop.
Save singe/a21b7c2e39187a4aa4368204c6790147 to your computer and use it in GitHub Desktop.
Simple canary token binary wrapper
#include "canary32.h"
// Modified from https://sourceforge.net/projects/cyoencode/
static const char* const BASE32_TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=";
size_t cyoBase32EncodeA(char* dest, const void* src, size_t srcBytes)
{
if (srcBytes > 153)
return 0; // Hostname max is 253, which means input can't be more than 153 I think
if (dest && src)
{
unsigned char* pSrc = (unsigned char*)src;
char* pDest = dest;
size_t dwSrcSize = srcBytes;
size_t dwDestSize = 0;
size_t dwBlockSize;
unsigned char n[8];
while (dwSrcSize >= 1)
{
/* Encode inputs */
dwBlockSize = (dwSrcSize < BASE32_INPUT ? dwSrcSize : BASE32_INPUT);
n[0] = n[1] = n[2] = n[3] = n[4] = n[5] = n[6] = n[7] = 0;
switch (dwBlockSize)
{
case 5:
n[7] = (pSrc[4] & 0x1f);
n[6] = ((pSrc[4] & 0xe0) >> 5);
case 4:
n[6] |= ((pSrc[3] & 0x03) << 3);
n[5] = ((pSrc[3] & 0x7c) >> 2);
n[4] = ((pSrc[3] & 0x80) >> 7);
case 3:
n[4] |= ((pSrc[2] & 0x0f) << 1);
n[3] = ((pSrc[2] & 0xf0) >> 4);
case 2:
n[3] |= ((pSrc[1] & 0x01) << 4);
n[2] = ((pSrc[1] & 0x3e) >> 1);
n[1] = ((pSrc[1] & 0xc0) >> 6);
case 1:
n[1] |= ((pSrc[0] & 0x07) << 2);
n[0] = ((pSrc[0] & 0xf8) >> 3);
break;
default:
assert(0);
}
pSrc += dwBlockSize;
dwSrcSize -= dwBlockSize;
/* Validate */
for (int i=0; i < 8; i++)
assert(n[i] <= 31);
/* Padding */
switch (dwBlockSize)
{
case 1: n[2] = n[3] = 32;
case 2: n[4] = 32;
case 3: n[5] = n[6] = 32;
case 4: n[7] = 32;
case 5:
break;
default:
assert(0);
}
/* 8 outputs */
for (int i=0; i < 8; i++) {
if (n[i] == 32) break;
dwDestSize++;
if (dwDestSize % 64 == 0) {
*pDest++ = '.';
dwDestSize++;
}
*pDest++ = BASE32_TABLE[n[i]];
}
}
*pDest++ = '\x0'; /*append terminator*/
//sranddev();
//int i = snprintf(dest, MAX_HOSTNAME, "%s.G%02d", dest, rand()%99);
srand(time(NULL));
char foo[MAX_HOSTNAME];
int i = snprintf(foo, MAX_HOSTNAME, "%s.G%02d", dest, rand()%99);
i = snprintf(dest, MAX_HOSTNAME, "%s", foo);
if (i >= MAX_HOSTNAME)
return 0; //encoded value exceeds hostname max
else
return i;
}
else
return 0; /*ERROR - null pointer*/
}
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define MAX_HOSTNAME 254
#define BASE32_INPUT 5
size_t cyoBase32EncodeA(char* dest, const void* src, size_t srcBytes);
FROM alpine:latest as builder
LABEL maintainer="@singe at SensePost <research@sensepost.com>"
RUN apk update && apk --no-cache add \
build-base \
&& rm -rf /var/cache/apk/*
WORKDIR /
COPY yellow.c canary32.c canary32.h /
RUN gcc -o yellow yellow.c canary32.c
From alpine:latest
LABEL maintainer="@singe at SensePost <research@sensepost.com>"
COPY --from=builder /yellow /bin/
RUN mv /usr/bin/id /usr/bin/id.canary \
&& ln -s /bin/yellow /usr/bin/id
/**
A simple library for triggering a canary token.
By @singe
Compile it as a shared library:
gcc -shared -fPIC libyellow.c canary32.c -o libyellow.so
Setup:
Register your own DNS canary token from Thinkst at https://canarytokens.org/
and place it in TOKEN below.
Put the library somewhere you're comfortable with, and put it in
LD_PRELOAD. For example:
cp libyellow.so /usr/lib
echo /usr/lib/libyellow.so >> /etc/ld.so.preload
Usage:
If anyone executes one of your binaries, you'll get a Canary notification.
**/
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
#include "canary32.h"
#define TOKEN "XXXX.canarytokens.com"
#define FILENAMESIZE 500
int yellow(int argc, char **argv, char **env)
{
struct addrinfo *res;
char hostname[MAX_HOSTNAME], fqdn[FILENAMESIZE];
int len = cyoBase32EncodeA(hostname, argv[0], strlen(argv[0]));
// Trigger our canary token
if (len == 0)
getaddrinfo(TOKEN,NULL,NULL,&res);
else {
snprintf(fqdn, FILENAMESIZE, "%s.%s", hostname, TOKEN);
getaddrinfo(fqdn,NULL,NULL,&res);
}
freeaddrinfo(res);
return 0;
}
__attribute__((section(".init_array"))) static void *foo_constructor = &yellow;
/**
A simple binary wrapper for triggering a canary token.
By @singe
Setup:
Register your own DNS canary token from Thinkst at https://canarytokens.org/
and place it in TOKEN below.
Move the legit binary to use the extension you defined below, then either
copy this binary to that or use a symlink. For example:
cp yellow /usr/bin
cd /usr/bin
mv id id.canary
ln -s yellow id
Compiling:
gcc -o yellow yellow.c canary32.c
Usage:
If anyone executes one of your binaries, you'll get a Canary notification.
**/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include "canary32.h"
#define TOKEN "XXXX.canarytokens.com"
// Use whatever extension you like
#define EXTENSION ".canary"
// 200 bytes should be enough for anyone - Not Bill Gates
#define FILENAMESIZE 500
int main(int argc, char *argv[], char *environ[])
{
struct addrinfo *res;
char hostname[MAX_HOSTNAME], fqdn[FILENAMESIZE];
int len = cyoBase32EncodeA(hostname, argv[0], strlen(argv[0]));
// Trigger our canary token
if (len == 0)
getaddrinfo(TOKEN,NULL,NULL,&res);
else {
snprintf(fqdn, FILENAMESIZE, "%s.%s", hostname, TOKEN);
getaddrinfo(fqdn,NULL,NULL,&res);
printf("%s",fqdn);
}
freeaddrinfo(res);
// Append our extension to the called filename to get the real one
char realexe[FILENAMESIZE];
snprintf(realexe, FILENAMESIZE, "%s.%s", argv[0], EXTENSION);
// PATH lookup the exec and replace this process with it
// Preserving the passed args and environment
execvp(realexe, argv);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment