这是一个double free的题啊,题目比较简单。
首先看一下这个文件:
这是一个64位的程序,动态链接的。
运行下看看:
再来用ida看一下这个程序代码(有些地方我有重新标记):
看一下list:
然后看下每一个流程是怎么执行的吧,发现无法解析伪c代码,那就看汇编结合动调吧。
.text:0000000000000B90 list proc near ; CODE XREF: main+30p .text:0000000000000B90 .text:0000000000000B90 var_8 = qword ptr -8 .text:0000000000000B90 .text:0000000000000B90 push rbp .text:0000000000000B91 mov rbp, rsp .text:0000000000000B94 sub rsp, 10h .text:0000000000000B98 mov rax, fs:28h .text:0000000000000BA1 mov [rbp+var_8], rax .text:0000000000000BA5 xor eax, eax .text:0000000000000BA7 lea rdi, s ; s .text:0000000000000BAE call puts .text:0000000000000BB3 lea rdi, asc_1355 ; " ,-,------, " .text:0000000000000BBA call puts .text:0000000000000BBF lea rdi, a__ ; " _ \\(\\(_,--‘ " .text:0000000000000BC6 call puts .text:0000000000000BCB lea rdi, a___0 ; " <`--‘\\>/(/(__ " .text:0000000000000BD2 call puts .text:0000000000000BD7 lea rdi, a___1 ; " /. . `‘` ‘ \\ " .text:0000000000000BDE call puts .text:0000000000000BE3 lea rdi, a@ ; " (‘‘) , @ " .text:0000000000000BEA call puts .text:0000000000000BEF lea rdi, a___2 ; " `-._, / " .text:0000000000000BF6 call puts .text:0000000000000BFB lea rdi, a_ ; " )-)_/--( > " .text:0000000000000C02 call puts .text:0000000000000C07 lea rdi, asc_13FD ; " ‘‘‘‘ ‘‘‘‘ " .text:0000000000000C0E call puts .text:0000000000000C13 lea rdi, s ; s .text:0000000000000C1A call puts .text:0000000000000C1F lea rdi, a1_RaiseAPig ; "1 . Raise a pig " .text:0000000000000C26 call puts .text:0000000000000C2B lea rdi, a2_VisitPigs ; "2 . Visit pigs " .text:0000000000000C32 call puts .text:0000000000000C37 lea rdi, a3_EatAPig ; "3 . Eat a pig" .text:0000000000000C3E call puts .text:0000000000000C43 lea rdi, a4_EatTheWholeP ; "4 . Eat the whole Pig Farm" .text:0000000000000C4A call puts .text:0000000000000C4F lea rdi, a5_LeaveTheFarm ; "5 . Leave the Farm" .text:0000000000000C56 call puts .text:0000000000000C5B lea rdi, s ; s .text:0000000000000C62 call puts .text:0000000000000C67 lea rdi, format ; "Your choice : " .text:0000000000000C6E mov eax, 0 .text:0000000000000C73 call printf .text:0000000000000C78 nop .text:0000000000000C79 mov rax, [rbp+var_8] .text:0000000000000C7D xor rax, fs:28h .text:0000000000000C86 jz short locret_C8D .text:0000000000000C88 call __stack_chk_fail .text:0000000000000C8D ; --------------------------------------------------------------------------- .text:0000000000000C8D .text:0000000000000C8D locret_C8D: ; CODE XREF: list+F6j .text:0000000000000C8D leave .text:0000000000000C8E retn .text:0000000000000C8E list endp .text:0000000000000C8E .text:0000000000000C8F .text:0000000000000C8F ; =============== S U B R O U T I N E ======================================= .text:0000000000000C8F .text:0000000000000C8F ; Attributes: bp-based frame .text:0000000000000C8F .text:0000000000000C8F sub_C8F proc near ; CODE XREF: main+89p .text:0000000000000C8F .text:0000000000000C8F size = qword ptr -20h .text:0000000000000C8F s = qword ptr -18h .text:0000000000000C8F buf = qword ptr -10h .text:0000000000000C8F var_8 = qword ptr -8 .text:0000000000000C8F .text:0000000000000C8F push rbp .text:0000000000000C90 mov rbp, rsp .text:0000000000000C93 sub rsp, 20h .text:0000000000000C97 mov rax, fs:28h .text:0000000000000CA0 mov [rbp+var_8], rax .text:0000000000000CA4 xor eax, eax .text:0000000000000CA6 push rax .text:0000000000000CA7 xor eax, eax .text:0000000000000CA9 jz short loc_CAF .text:0000000000000CAB add rsp, 4 .text:0000000000000CAF .text:0000000000000CAF loc_CAF: ; CODE XREF: sub_C8F+1Aj .text:0000000000000CAF pop rax .text:0000000000000CB0 mov [rbp+s], 0 .text:0000000000000CB8 mov [rbp+buf], 0 .text:0000000000000CC0 mov dword ptr [rbp+size], 0 .text:0000000000000CC7 mov eax, cs:dword_20202C .text:0000000000000CCD cmp eax, 63h .text:0000000000000CD0 ja loc_E23 .text:0000000000000CD6 mov edi, 28h ; size .text:0000000000000CDB call malloc //申请一个堆 .text:0000000000000CE0 mov [rbp+s], rax .text:0000000000000CE4 mov rax, [rbp+s] .text:0000000000000CE8 mov edx, 28h ; n .text:0000000000000CED mov esi, 0 ; c .text:0000000000000CF2 mov rdi, rax ; s .text:0000000000000CF5 call memset .text:0000000000000CFA lea rdi, aLengthOfTheNam ; "Length of the name :" //这里是我们输入的raise的length .text:0000000000000D01 mov eax, 0 .text:0000000000000D06 call printf .text:0000000000000D0B lea rax, [rbp+size] .text:0000000000000D0F mov rsi, rax .text:0000000000000D12 lea rdi, aU ; "%u" .text:0000000000000D19 mov eax, 0 .text:0000000000000D1E call __isoc99_scanf .text:0000000000000D23 cmp eax, 0FFFFFFFFh .text:0000000000000D26 jnz short loc_D32 .text:0000000000000D28 mov edi, 0FFFFFFFFh ; status .text:0000000000000D2D call exit .text:0000000000000D32 ; --------------------------------------------------------------------------- .text:0000000000000D32 .text:0000000000000D32 loc_D32: ; CODE XREF: sub_C8F+97j .text:0000000000000D32 mov eax, dword ptr [rbp+size] .text:0000000000000D35 mov eax, eax .text:0000000000000D37 mov rdi, rax ; size .text:0000000000000D3A call malloc //然后申请一个堆 .text:0000000000000D3F mov [rbp+buf], rax .text:0000000000000D43 cmp [rbp+buf], 0 .text:0000000000000D48 jnz short loc_D60 .text:0000000000000D4A lea rdi, aError ; "error !" .text:0000000000000D51 call puts .text:0000000000000D56 mov edi, 0FFFFFFFFh ; status .text:0000000000000D5B call exit .text:0000000000000D60 ; --------------------------------------------------------------------------- .text:0000000000000D60 .text:0000000000000D60 loc_D60: ; CODE XREF: sub_C8F+B9j .text:0000000000000D60 lea rdi, aTheNameOfPig ; "The name of pig :" .text:0000000000000D67 mov eax, 0 .text:0000000000000D6C call printf .text:0000000000000D71 mov eax, dword ptr [rbp+size] .text:0000000000000D74 mov edx, eax ; nbytes .text:0000000000000D76 mov rax, [rbp+buf] .text:0000000000000D7A mov rsi, rax ; buf .text:0000000000000D7D mov edi, 0 ; fd .text:0000000000000D82 call read .text:0000000000000D87 mov rax, [rbp+s] .text:0000000000000D8B mov rdx, [rbp+buf] .text:0000000000000D8F mov [rax+8], rdx .text:0000000000000D93 lea rdi, aTheTypeOfThePi ; "The type of the pig :" //获取参数:type .text:0000000000000D9A mov eax, 0 .text:0000000000000D9F call printf .text:0000000000000DA4 mov rax, [rbp+s] .text:0000000000000DA8 add rax, 10h .text:0000000000000DAC mov rsi, rax .text:0000000000000DAF lea rdi, a23s ; "%23s" .text:0000000000000DB6 mov eax, 0 .text:0000000000000DBB call __isoc99_scanf .text:0000000000000DC0 mov rax, [rbp+s] .text:0000000000000DC4 mov dword ptr [rax], 1 .text:0000000000000DCA mov dword ptr [rbp+size+4], 0 .text:0000000000000DD1 jmp short loc_E0E .text:0000000000000DD3 ; --------------------------------------------------------------------------- .text:0000000000000DD3
看一下内存分配,可以看出来Name放在一个堆里,type放在了另外一个堆里:
然后删除第一个堆,看下内存分配:
可以发现之前的name的空间被free了,然后我们在申请一个内存,看看位置。
也就是说free的空间是Name所在的空间。第0个空间就会释放AAAA空间,第1个就是释放BBBB空间。同理……
下面就可以进行利用了,思路:
1.泄露libc地址,并通过偏移计算出__malloc_hook函数地址,one_gadget获得的system"/bin/sh"的地址。
2.修改__malloc_hook函数的地址为我们的system"/bin/sh"的地址
3.double free 触发__malloc_hook执行,便会转换到执行我们的shell。
那么我们开始写脚本吧,