Attachment:
#define _GNU_SOURCE
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <stdbool.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <unistd.h>
static volatile sig_atomic_t stop;
static void handle_sigint(int sig)
{
(void)sig;
stop = 1;
}
static int libbpf_print_fn(enum libbpf_print_level level,
const char *fmt, va_list args)
{
return vfprintf(stderr, fmt, args);
}
static void broadcast_cheer(void)
{
libbpf_set_print(libbpf_print_fn);
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
DIR *d = opendir("/dev/pts");
struct dirent *de;
char path[64];
char flag[256];
char banner[512];
ssize_t n;
if (!d)
return;
int ffd = open("/flag", O_RDONLY | O_CLOEXEC);
if (ffd >= 0) {
n = read(ffd, flag, sizeof(flag) - 1);
if (n >= 0)
flag[n] = '\0';
close(ffd);
} else {
strcpy(flag, "no-flag\n");
}
snprintf(
banner,
sizeof(banner),
"🎅 🎄 🎁 \x1b[1;31mHo Ho Ho\x1b[0m, \x1b[1;32mMerry Christmas!\x1b[0m\n"
"%s",
flag);
while ((de = readdir(d)) != NULL) {
const char *name = de->d_name;
size_t len = strlen(name);
bool all_digits = true;
if (len == 0 || name[0] == '.')
continue;
if (strcmp(name, "ptmx") == 0)
continue;
for (size_t i = 0; i < len; i++) {
if (!isdigit((unsigned char)name[i])) {
all_digits = false;
break;
}
}
if (!all_digits)
continue;
snprintf(path, sizeof(path), "/dev/pts/%s", name);
int fd = open(path, O_WRONLY | O_NOCTTY | O_CLOEXEC);
if (fd < 0)
continue;
write(fd, "\x1b[2J\x1b[H", 7);
write(fd, banner, strlen(banner));
close(fd);
}
closedir(d);
}
int main(void)
{
struct bpf_object *obj = NULL;
struct bpf_program *prog = NULL;
struct bpf_link *link = NULL;
struct bpf_map *success = NULL;
int map_fd;
__u32 key0 = 0;
int err;
int should_broadcast = 0;
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
setvbuf(stdout, NULL, _IONBF, 0);
obj = bpf_object__open_file("/challenge/tracker.bpf.o", NULL);
if (!obj) {
fprintf(stderr, "Failed to open BPF object: %s\n", strerror(errno));
return 1;
}
err = bpf_object__load(obj);
if (err) {
fprintf(stderr, "Failed to load BPF object: %s\n", strerror(-err));
goto cleanup;
}
prog = bpf_object__find_program_by_name(obj, "handle_do_linkat");
if (!prog) {
fprintf(stderr, "Could not find BPF program handle_do_linkat\n");
goto cleanup;
}
link = bpf_program__attach_kprobe(prog, false, "__x64_sys_linkat");
if (!link) {
fprintf(stderr, "Failed to attach kprobe __x64_sys_linkat: %s\n", strerror(errno));
goto cleanup;
}
signal(SIGINT, handle_sigint);
signal(SIGTERM, handle_sigint);
success = bpf_object__find_map_by_name(obj, "success");
if (!success) {
fprintf(stderr, "Failed to find success map\n");
goto cleanup;
}
map_fd = bpf_map__fd(success);
printf("Attached. Press Ctrl-C to quit.\n");
fflush(stdout);
while (!stop) {
__u32 v = 0;
if (bpf_map_lookup_elem(map_fd, &key0, &v) == 0 && v != 0) {
should_broadcast = 1;
stop = 1;
break;
}
usleep(100000);
}
if (should_broadcast)
broadcast_cheer();
cleanup:
if (link)
bpf_link__destroy(link);
if (obj)
bpf_object__close(obj);
return err ? 1 : 0;
}
It loads an eBPF program and waits for it success signal. We need to reverse engineer the eBPF bytecode:
bpf-objdump -d tracker.bpf.o > dump.S
With the assist of AI (see below), the bpf code hooked to linkat syscall does the following things:
progress map, validate the second path with dasher, dancer, prancer, vixen, comet, cupid, donner and blitzen respectivelyExperiment in privileged mode:
hacker@practice~2025~day-04:~$ sudo bpftool map list
1: array name progress flags 0x0
key 4B value 4B max_entries 1 memlock 272B
btf_id 12
2: array name success flags 0x0
key 4B value 4B max_entries 1 memlock 272B
btf_id 12
hacker@practice~2025~day-04:~$ sudo bpftool map dump id 1
[{
"key": 0,
"value": 0
}
]
hacker@practice~2025~day-04:~$ ln sleigh dasher
ln: failed to create hard link 'dasher': File exists
hacker@practice~2025~day-04:~$ sudo bpftool map dump id 1
[{
"key": 0,
"value": 1
}
]
hacker@practice~2025~day-04:~$ sudo bpftool map dump id 1
[{
"key": 0,
"value": 2
}
]
It matches our expectation. So we run the following commands in unprivileged mode to get flag (launch tmux if via ssh):
ln sleigh dasher
ln sleigh dancer
ln sleigh prancer
ln sleigh vixen
ln sleigh comet
ln sleigh cupid
ln sleigh donner
ln sleigh blitzen
The annotated assembly:
tracker.bpf.o: file format elf64-bpfle
Disassembly of section kprobe/__x64_sys_linkat:
0000000000000000 <handle_do_linkat>:
0: 79 16 70 00 00 00 00 00 ldxdw %r6,[%r1+112]
8: b7 01 00 00 00 00 00 00 mov %r1,0
10: 7b 1a d0 ff 00 00 00 00 stxdw [%r10-48],%r1
18: 7b 1a c8 ff 00 00 00 00 stxdw [%r10-56],%r1
20: 15 06 0e 01 00 00 00 00 jeq %r6,0,270
# read argument to r10-48
28: bf 63 00 00 00 00 00 00 mov %r3,%r6
30: 07 03 00 00 68 00 00 00 add %r3,104
38: bf a1 00 00 00 00 00 00 mov %r1,%r10
40: 07 01 00 00 d0 ff ff ff add %r1,-48
48: b7 02 00 00 08 00 00 00 mov %r2,8
50: 85 00 00 00 71 00 00 00 call 113
# read argument to r10-56
58: 07 06 00 00 38 00 00 00 add %r6,56
60: bf a1 00 00 00 00 00 00 mov %r1,%r10
68: 07 01 00 00 c8 ff ff ff add %r1,-56
70: b7 02 00 00 08 00 00 00 mov %r2,8
78: bf 63 00 00 00 00 00 00 mov %r3,%r6
80: 85 00 00 00 71 00 00 00 call 113
88: 79 a3 d0 ff 00 00 00 00 ldxdw %r3,[%r10-48]
90: 15 03 00 01 00 00 00 00 jeq %r3,0,256
98: 79 a1 c8 ff 00 00 00 00 ldxdw %r1,[%r10-56]
a0: 15 01 fe 00 00 00 00 00 jeq %r1,0,254
# read string to r10-40
a8: bf a1 00 00 00 00 00 00 mov %r1,%r10
b0: 07 01 00 00 d8 ff ff ff add %r1,-40
b8: b7 02 00 00 10 00 00 00 mov %r2,16
c0: 85 00 00 00 72 00 00 00 call 114
c8: 67 00 00 00 20 00 00 00 lsh %r0,32
d0: c7 00 00 00 20 00 00 00 arsh %r0,32
d8: b7 01 00 00 01 00 00 00 mov %r1,1
e0: 6d 01 f6 00 00 00 00 00 jsgt %r1,%r0,246
# read string to r10-16
e8: 79 a3 d0 ff 00 00 00 00 ldxdw %r3,[%r10-48]
f0: bf a1 00 00 00 00 00 00 mov %r1,%r10
f8: 07 01 00 00 f0 ff ff ff add %r1,-16
100: b7 02 00 00 10 00 00 00 mov %r2,16
108: 85 00 00 00 72 00 00 00 call 114
110: 67 00 00 00 20 00 00 00 lsh %r0,32
118: 77 00 00 00 20 00 00 00 rsh %r0,32
120: 55 00 ee 00 07 00 00 00 jne %r0,7,238
# compare with "sleigh"
128: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
130: 55 01 ec 00 73 00 00 00 jne %r1,115,236
138: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
140: 55 01 ea 00 6c 00 00 00 jne %r1,108,234
148: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
150: 55 01 e8 00 65 00 00 00 jne %r1,101,232
158: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
160: 55 01 e6 00 69 00 00 00 jne %r1,105,230
168: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
170: 55 01 e4 00 67 00 00 00 jne %r1,103,228
178: 71 a1 f5 ff 00 00 00 00 ldxb %r1,[%r10-11]
180: 55 01 e2 00 68 00 00 00 jne %r1,104,226
188: 79 a3 c8 ff 00 00 00 00 ldxdw %r3,[%r10-56]
190: bf a1 00 00 00 00 00 00 mov %r1,%r10
198: 07 01 00 00 d8 ff ff ff add %r1,-40
1a0: b7 02 00 00 10 00 00 00 mov %r2,16
1a8: 85 00 00 00 72 00 00 00 call 114
1b0: 67 00 00 00 20 00 00 00 lsh %r0,32
1b8: c7 00 00 00 20 00 00 00 arsh %r0,32
1c0: b7 01 00 00 01 00 00 00 mov %r1,1
1c8: 6d 01 d9 00 00 00 00 00 jsgt %r1,%r0,217
1d0: 79 a6 c8 ff 00 00 00 00 ldxdw %r6,[%r10-56]
1d8: b7 07 00 00 00 00 00 00 mov %r7,0
1e0: 63 7a ec ff 00 00 00 00 stxw [%r10-20],%r7
1e8: bf a2 00 00 00 00 00 00 mov %r2,%r10
1f0: 07 02 00 00 ec ff ff ff add %r2,-20
1f8: 18 01 00 00 00 00 00 00 lddw %r1,0
200: 00 00 00 00 00 00 00 00
208: 85 00 00 00 01 00 00 00 call 1
210: 15 00 01 00 00 00 00 00 jeq %r0,0,1
218: 61 07 00 00 00 00 00 00 ldxw %r7,[%r0+0]
220: bf a1 00 00 00 00 00 00 mov %r1,%r10
228: 07 01 00 00 f0 ff ff ff add %r1,-16
230: b7 02 00 00 10 00 00 00 mov %r2,16
238: bf 63 00 00 00 00 00 00 mov %r3,%r6
240: 85 00 00 00 72 00 00 00 call 114
248: 67 00 00 00 20 00 00 00 lsh %r0,32
250: 77 00 00 00 20 00 00 00 rsh %r0,32
258: 55 00 0e 00 07 00 00 00 jne %r0,7,14
# compare with "dasher", set to 1
260: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
268: 55 01 0c 00 64 00 00 00 jne %r1,100,12
270: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
278: 55 01 0a 00 61 00 00 00 jne %r1,97,10
280: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
288: 55 01 08 00 73 00 00 00 jne %r1,115,8
290: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
298: 55 01 06 00 68 00 00 00 jne %r1,104,6
2a0: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
2a8: 55 01 04 00 65 00 00 00 jne %r1,101,4
2b0: 71 a1 f5 ff 00 00 00 00 ldxb %r1,[%r10-11]
2b8: 55 01 02 00 72 00 00 00 jne %r1,114,2
2c0: b7 01 00 00 01 00 00 00 mov %r1,1
2c8: 05 00 b0 00 00 00 00 00 ja 176
2d0: 65 07 18 00 03 00 00 00 jsgt %r7,3,24
2d8: 15 07 55 00 01 00 00 00 jeq %r7,1,85
2e0: 15 07 94 00 02 00 00 00 jeq %r7,2,148
2e8: 15 07 01 00 03 00 00 00 jeq %r7,3,1
2f0: 05 00 aa 00 00 00 00 00 ja 170
2f8: bf a1 00 00 00 00 00 00 mov %r1,%r10
300: 07 01 00 00 f0 ff ff ff add %r1,-16
308: b7 02 00 00 10 00 00 00 mov %r2,16
310: bf 63 00 00 00 00 00 00 mov %r3,%r6
318: 85 00 00 00 72 00 00 00 call 114
320: 67 00 00 00 20 00 00 00 lsh %r0,32
328: 77 00 00 00 20 00 00 00 rsh %r0,32
330: 55 00 a2 00 06 00 00 00 jne %r0,6,162
# compare with "vixen", set to 4
338: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
340: 55 01 a0 00 76 00 00 00 jne %r1,118,160
348: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
350: 55 01 9e 00 69 00 00 00 jne %r1,105,158
358: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
360: 55 01 9c 00 78 00 00 00 jne %r1,120,156
368: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
370: 55 01 9a 00 65 00 00 00 jne %r1,101,154
378: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
380: 55 01 98 00 6e 00 00 00 jne %r1,110,152
388: b7 01 00 00 04 00 00 00 mov %r1,4
390: 05 00 97 00 00 00 00 00 ja 151
398: 65 07 17 00 05 00 00 00 jsgt %r7,5,23
3a0: 15 07 52 00 04 00 00 00 jeq %r7,4,82
3a8: 15 07 01 00 05 00 00 00 jeq %r7,5,1
3b0: 05 00 92 00 00 00 00 00 ja 146
3b8: bf a1 00 00 00 00 00 00 mov %r1,%r10
3c0: 07 01 00 00 f0 ff ff ff add %r1,-16
3c8: b7 02 00 00 10 00 00 00 mov %r2,16
3d0: bf 63 00 00 00 00 00 00 mov %r3,%r6
3d8: 85 00 00 00 72 00 00 00 call 114
3e0: 67 00 00 00 20 00 00 00 lsh %r0,32
3e8: 77 00 00 00 20 00 00 00 rsh %r0,32
3f0: 55 00 8a 00 06 00 00 00 jne %r0,6,138
# compare with "cupid", set to 6
3f8: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
400: 55 01 88 00 63 00 00 00 jne %r1,99,136
408: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
410: 55 01 86 00 75 00 00 00 jne %r1,117,134
418: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
420: 55 01 84 00 70 00 00 00 jne %r1,112,132
428: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
430: 55 01 82 00 69 00 00 00 jne %r1,105,130
438: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
440: 55 01 80 00 64 00 00 00 jne %r1,100,128
448: b7 01 00 00 06 00 00 00 mov %r1,6
450: 05 00 7f 00 00 00 00 00 ja 127
458: 15 07 4f 00 06 00 00 00 jeq %r7,6,79
460: 15 07 01 00 07 00 00 00 jeq %r7,7,1
468: 05 00 7b 00 00 00 00 00 ja 123
470: bf a1 00 00 00 00 00 00 mov %r1,%r10
478: 07 01 00 00 f0 ff ff ff add %r1,-16
480: b7 02 00 00 10 00 00 00 mov %r2,16
488: bf 63 00 00 00 00 00 00 mov %r3,%r6
490: 85 00 00 00 72 00 00 00 call 114
498: 67 00 00 00 20 00 00 00 lsh %r0,32
4a0: 77 00 00 00 20 00 00 00 rsh %r0,32
4a8: 55 00 73 00 08 00 00 00 jne %r0,8,115
# compare with "blitzen", finish
4b0: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
4b8: 55 01 71 00 62 00 00 00 jne %r1,98,113
4c0: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
4c8: 55 01 6f 00 6c 00 00 00 jne %r1,108,111
4d0: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
4d8: 55 01 6d 00 69 00 00 00 jne %r1,105,109
4e0: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
4e8: 55 01 6b 00 74 00 00 00 jne %r1,116,107
4f0: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
4f8: 55 01 69 00 7a 00 00 00 jne %r1,122,105
500: 71 a1 f5 ff 00 00 00 00 ldxb %r1,[%r10-11]
508: 55 01 67 00 65 00 00 00 jne %r1,101,103
510: 71 a1 f6 ff 00 00 00 00 ldxb %r1,[%r10-10]
518: 55 01 65 00 6e 00 00 00 jne %r1,110,101
520: b7 01 00 00 08 00 00 00 mov %r1,8
528: 63 1a e8 ff 00 00 00 00 stxw [%r10-24],%r1
530: b7 01 00 00 01 00 00 00 mov %r1,1
538: 63 1a f0 ff 00 00 00 00 stxw [%r10-16],%r1
540: bf a2 00 00 00 00 00 00 mov %r2,%r10
548: 07 02 00 00 ec ff ff ff add %r2,-20
550: bf a3 00 00 00 00 00 00 mov %r3,%r10
558: 07 03 00 00 f0 ff ff ff add %r3,-16
560: 18 01 00 00 00 00 00 00 lddw %r1,0
568: 00 00 00 00 00 00 00 00
570: b7 04 00 00 00 00 00 00 mov %r4,0
578: 85 00 00 00 02 00 00 00 call 2
580: 05 00 5a 00 00 00 00 00 ja 90
588: bf a1 00 00 00 00 00 00 mov %r1,%r10
590: 07 01 00 00 f0 ff ff ff add %r1,-16
598: b7 02 00 00 10 00 00 00 mov %r2,16
5a0: bf 63 00 00 00 00 00 00 mov %r3,%r6
5a8: 85 00 00 00 72 00 00 00 call 114
5b0: 67 00 00 00 20 00 00 00 lsh %r0,32
5b8: 77 00 00 00 20 00 00 00 rsh %r0,32
5c0: 55 00 50 00 07 00 00 00 jne %r0,7,80
# compare with "dancer", set to 2
5c8: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
5d0: 55 01 4e 00 64 00 00 00 jne %r1,100,78
5d8: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
5e0: 55 01 4c 00 61 00 00 00 jne %r1,97,76
5e8: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
5f0: 55 01 4a 00 6e 00 00 00 jne %r1,110,74
5f8: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
600: 55 01 48 00 63 00 00 00 jne %r1,99,72
608: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
610: 55 01 46 00 65 00 00 00 jne %r1,101,70
618: 71 a1 f5 ff 00 00 00 00 ldxb %r1,[%r10-11]
620: 55 01 44 00 72 00 00 00 jne %r1,114,68
628: b7 01 00 00 02 00 00 00 mov %r1,2
630: 05 00 43 00 00 00 00 00 ja 67
638: bf a1 00 00 00 00 00 00 mov %r1,%r10
640: 07 01 00 00 f0 ff ff ff add %r1,-16
648: b7 02 00 00 10 00 00 00 mov %r2,16
650: bf 63 00 00 00 00 00 00 mov %r3,%r6
658: 85 00 00 00 72 00 00 00 call 114
660: 67 00 00 00 20 00 00 00 lsh %r0,32
668: 77 00 00 00 20 00 00 00 rsh %r0,32
670: 55 00 3a 00 06 00 00 00 jne %r0,6,58
# compare with "comet", set to 5
678: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
680: 55 01 38 00 63 00 00 00 jne %r1,99,56
688: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
690: 55 01 36 00 6f 00 00 00 jne %r1,111,54
698: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
6a0: 55 01 34 00 6d 00 00 00 jne %r1,109,52
6a8: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
6b0: 55 01 32 00 65 00 00 00 jne %r1,101,50
6b8: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
6c0: 55 01 30 00 74 00 00 00 jne %r1,116,48
6c8: b7 01 00 00 05 00 00 00 mov %r1,5
6d0: 05 00 2f 00 00 00 00 00 ja 47
6d8: bf a1 00 00 00 00 00 00 mov %r1,%r10
6e0: 07 01 00 00 f0 ff ff ff add %r1,-16
6e8: b7 02 00 00 10 00 00 00 mov %r2,16
6f0: bf 63 00 00 00 00 00 00 mov %r3,%r6
6f8: 85 00 00 00 72 00 00 00 call 114
700: 67 00 00 00 20 00 00 00 lsh %r0,32
708: 77 00 00 00 20 00 00 00 rsh %r0,32
710: 55 00 26 00 07 00 00 00 jne %r0,7,38
# compare with "donner", set to 7
718: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
720: 55 01 24 00 64 00 00 00 jne %r1,100,36
728: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
730: 55 01 22 00 6f 00 00 00 jne %r1,111,34
738: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
740: 55 01 20 00 6e 00 00 00 jne %r1,110,32
748: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
750: 55 01 1e 00 6e 00 00 00 jne %r1,110,30
758: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
760: 55 01 1c 00 65 00 00 00 jne %r1,101,28
768: 71 a1 f5 ff 00 00 00 00 ldxb %r1,[%r10-11]
770: 55 01 1a 00 72 00 00 00 jne %r1,114,26
778: b7 01 00 00 07 00 00 00 mov %r1,7
780: 05 00 19 00 00 00 00 00 ja 25
788: bf a1 00 00 00 00 00 00 mov %r1,%r10
790: 07 01 00 00 f0 ff ff ff add %r1,-16
798: b7 02 00 00 10 00 00 00 mov %r2,16
7a0: bf 63 00 00 00 00 00 00 mov %r3,%r6
7a8: 85 00 00 00 72 00 00 00 call 114
7b0: 67 00 00 00 20 00 00 00 lsh %r0,32
7b8: 77 00 00 00 20 00 00 00 rsh %r0,32
7c0: 55 00 10 00 08 00 00 00 jne %r0,8,16
# compare with "prancer", set to 3
7c8: 71 a1 f0 ff 00 00 00 00 ldxb %r1,[%r10-16]
7d0: 55 01 0e 00 70 00 00 00 jne %r1,112,14
7d8: 71 a1 f1 ff 00 00 00 00 ldxb %r1,[%r10-15]
7e0: 55 01 0c 00 72 00 00 00 jne %r1,114,12
7e8: 71 a1 f2 ff 00 00 00 00 ldxb %r1,[%r10-14]
7f0: 55 01 0a 00 61 00 00 00 jne %r1,97,10
7f8: 71 a1 f3 ff 00 00 00 00 ldxb %r1,[%r10-13]
800: 55 01 08 00 6e 00 00 00 jne %r1,110,8
808: 71 a1 f4 ff 00 00 00 00 ldxb %r1,[%r10-12]
810: 55 01 06 00 63 00 00 00 jne %r1,99,6
818: 71 a1 f5 ff 00 00 00 00 ldxb %r1,[%r10-11]
820: 55 01 04 00 65 00 00 00 jne %r1,101,4
828: 71 a1 f6 ff 00 00 00 00 ldxb %r1,[%r10-10]
830: 55 01 02 00 72 00 00 00 jne %r1,114,2
838: b7 01 00 00 03 00 00 00 mov %r1,3
840: 05 00 01 00 00 00 00 00 ja 1
848: b7 01 00 00 00 00 00 00 mov %r1,0
850: 63 1a e8 ff 00 00 00 00 stxw [%r10-24],%r1
858: bf a2 00 00 00 00 00 00 mov %r2,%r10
860: 07 02 00 00 ec ff ff ff add %r2,-20
868: bf a3 00 00 00 00 00 00 mov %r3,%r10
870: 07 03 00 00 e8 ff ff ff add %r3,-24
878: 18 01 00 00 00 00 00 00 lddw %r1,0
880: 00 00 00 00 00 00 00 00
888: b7 04 00 00 00 00 00 00 mov %r4,0
890: 85 00 00 00 02 00 00 00 call 2
898: b7 00 00 00 00 00 00 00 mov %r0,0
8a0: 95 00 00 00 00 00 00 00 exit
# order:
ln sleigh dasher
ln sleigh dancer
ln sleigh prancer
ln sleigh vixen
ln sleigh comet
ln sleigh cupid
ln sleigh donner
ln sleigh blitzen
The following analysis is done by DeepSeek:
Looking at this BPF assembly code for the handle_do_linkat function attached to __x64_sys_linkat, I can see it’s implementing a complex state machine that appears to be checking for specific paths in the linkat system call and performing a series of string comparisons.
[%r1+112] (old path)[%r1+70] (new path)State Machine: The code uses %r7 as a state variable and implements what appears to be a sequence of required paths. It checks for different strings based on the current state.
bpf_map_lookup_elem and bpf_map_update_elem. When the correct sequence is followed, it should update a map that the C program is monitoring.To trigger the success condition and cause broadcast_cheer() to be called, you need to call the linkat system call with specific paths that satisfy the state machine. Based on the string comparisons, it seems you need to create hard links with specific names.
The simplest approach would be to try creating a hard link from a source named “sleigh” to a destination named “dasher”:
# Create the source file
touch /tmp/sleigh
# Make the linkat system call
linkat(AT_FDCWD, "/tmp/sleigh", AT_FDCWD, "/tmp/dasher", 0)
Or using the command line:
ln /tmp/sleigh /tmp/dasher
The BPF program appears to be implementing a Christmas-themed challenge where you need to link “sleigh” to various reindeer names in sequence. You might need to make multiple calls with different destination names to progress through the state machine.
Given the complexity, you might need to try:
linkat(..., "sleigh", ..., "dasher", ...)linkat(..., "sleigh", ..., "vixen", ...)linkat(..., "sleigh", ..., "comet", ...)
…and so on through the sequence of reindeer names found in the assembly.You can use a simple C program to make the syscall directly:
#include <fcntl.h>
#include <unistd.h>
int main() {
// Create source file
int fd = open("/tmp/sleigh", O_CREAT | O_RDWR, 0644);
close(fd);
// Make the linkat syscall
syscall(SYS_linkat, AT_FDCWD, "/tmp/sleigh", AT_FDCWD, "/tmp/dasher", 0);
return 0;
}
Note: The exact behavior depends on the full state machine implemented in the BPF code, which tracks state in a BPF map. You may need to make multiple calls with different destination names to satisfy all the conditions.