最近在刷题的时候发现的一道相对简单的溢出题目,但是可能对堆溢出方面知识涉及的不多,导致花了不少时间去研究原理,感觉还有有不少收获的。
代开界面就是一个简单的宾馆预定系统
使用IDA分析函数,主要的函数包括mian(),book_suite(),book_room(),delete_booking(),print_booking()还有最主要的flag().
首先在main函数里会给个五个选择,预定suite、room,删除预定,打印预定,退出。
首先分析book_suite(),大致的情形就是在堆上申请了264个字节的空间,前四个字节储存print_name()函数,256个字节储存name,另外四个存储suite nummber。
Dump of assembler code for function book_suite:
0x0804873b <+0>: push %ebp
0x0804873c <+1>: mov %esp,%ebp
0x0804873e <+3>: push %ebx
0x0804873f <+4>: sub $0x34,%esp
0x08048742 <+7>: mov %gs:0x14,%eax
0x08048748 <+13>: mov %eax,-0xc(%ebp)
0x0804874b <+16>: xor %eax,%eax
0x0804874d <+18>: movl $0x108,(%esp) -->Allocate 264 bytes in heap memory
0x08048754 <+25>: call 0x80484e0 <malloc@plt> --> return ptr to memory in eax
0x08048759 <+30>: mov %eax,0x804b088 --> assign ptr to variable suite
0x0804875e <+35>: movl $0x8049688,(%esp)
0x08048765 <+42>: call 0x8048490 <printf@plt> --> print "Name:"
0x0804876a <+47>: mov 0x804b080,%eax
0x0804876f <+52>: mov %eax,(%esp)
0x08048772 <+55>: call 0x80484a0 <fflush@plt>
0x08048777 <+60>: mov 0x804b060,%eax
0x0804877c <+65>: mov 0x804b088,%edx --> variable suite
0x08048782 <+71>: add $0x4,%edx
0x08048785 <+74>: mov %eax,0x8(%esp)
0x08048789 <+78>: movl $0x100,0x4(%esp)--> length 0x100(256 bytes)
0x08048791 <+86>: mov %edx,(%esp)
0x08048794 <+89>: call 0x80484c0 <fgets@plt>--> read from stdin, store name at address suite+4, length 0x100(256 bytes)
0x08048799 <+94>: mov 0x804b088,%eax --> var suite into eax
0x0804879e <+99>: movl $0x8048a84,(%eax)--> store address of print_name function(0x8048a84) into memory location at suite
0x080487a4 <+105>: movl $0x804968f,(%esp) -->"Suite number:"
0x080487ab <+112>: call 0x8048490 <printf@plt>
0x080487b0 <+117>: mov 0x804b080,%eax
0x080487b5 <+122>: mov %eax,(%esp)
0x080487b8 <+125>: call 0x80484a0 <fflush@plt>
0x080487bd <+130>: mov 0x804b060,%eax -->stdin
0x080487c2 <+135>: mov %eax,0x8(%esp) -->push stdin stream
0x080487c6 <+139>: movl $0x10,0x4(%esp) -->read only 16bytes from stdin. *Cannot stack overflow*
0x080487ce <+147>: lea -0x1c(%ebp),%eax -->store in stack starting at $ebp-0x1c (28bytes away from base of stack)
0x080487d1 <+150>: mov %eax,(%esp)
0x080487d4 <+153>: call 0x80484c0 <fgets@plt> --> get suite number from stdin and store in stack
0x080487d9 <+158>: mov 0x804b088,%ebx --> pointer suite
0x080487df <+164>: lea -0x1c(%ebp),%eax
0x080487e2 <+167>: mov %eax,(%esp)
0x080487e5 <+170>: call 0x8048530 <atoi@plt>
0x080487ea <+175>: mov %eax,0x104(%ebx)--> save integer result into suite+0x104
0x080487f0 <+181>: movl $0x804969e,(%esp) --> "Booked a suite!"
0x080487f7 <+188>: call 0x80484f0 <puts@plt>
0x080487fc <+193>: mov 0x804b080,%eax
0x08048801 <+198>: mov %eax,(%esp)
0x08048804 <+201>: call 0x80484a0 <fflush@plt>
0x08048809 <+206>: mov -0xc(%ebp),%eax -->Stack canary
0x0804880c <+209>: xor %gs:0x14,%eax
0x08048813 <+216>: je 0x804881a <book_suite+223>
0x08048815 <+218>: call 0x80484d0 <__stack_chk_fail@plt>
0x0804881a <+223>: add $0x34,%esp
0x0804881d <+226>: pop %ebx
0x0804881e <+227>: pop %ebp
0x0804881f <+228>: ret
End of assembler dump.
使用gdb查看堆地址分配,第一个地址就是print_name()函数的地址。
(gdb) x/100wx suite
0x804c008: 0x08048a84(func) 0x62626262 0x00000a62 0x00000000
0x804c018: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c028: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c048: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c058: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c068: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c078: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c088: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c098: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0a8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0b8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0c8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0d8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0e8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0f8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c108: 0x00000000 0x0804863d(int) 0x00000000 0x00020ef1
0x804c118: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c128: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c138: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c148: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c158: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c168: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c178: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c188: 0x00000000 0x00000000 0x00000000 0x00000000
接下里是book_room函数,分配了大小为260的堆内存,256大小的向内存储存name,剩下4个字节储存room_nummber.
(gdb) disass book_room
Dump of assembler code for function book_room:
0x08048820 <+0>: push %ebp
0x08048821 <+1>: mov %esp,%ebp
0x08048823 <+3>: push %ebx
0x08048824 <+4>: sub $0x34,%esp
0x08048827 <+7>: mov %gs:0x14,%eax
0x0804882d <+13>: mov %eax,-0xc(%ebp)
0x08048830 <+16>: xor %eax,%eax
0x08048832 <+18>: movl $0x104,(%esp)
0x08048839 <+25>: call 0x80484e0 <malloc@plt>--> allocate 260 bytes in heap
0x0804883e <+30>: mov %eax,0x804b08c --> save pointer to variable room
0x08048843 <+35>: movl $0x8049688,(%esp) --> "Name: "
0x0804884a <+42>: call 0x8048490 <printf@plt>
0x0804884f <+47>: mov 0x804b080,%eax
0x08048854 <+52>: mov %eax,(%esp)
0x08048857 <+55>: call 0x80484a0 <fflush@plt>
0x0804885c <+60>: mov 0x804b060,%eax
0x08048861 <+65>: mov 0x804b08c,%edx --> variable room
0x08048867 <+71>: add $0x4,%edx
0x0804886a <+74>: mov %eax,0x8(%esp)
0x0804886e <+78>: movl $0x100,0x4(%esp)
0x08048876 <+86>: mov %edx,(%esp)
0x08048879 <+89>: call 0x80484c0 <fgets@plt> --> read from stdin, store name at address room+4, length 0x100(256 bytes)
0x0804887e <+94>: movl $0x80496ae,(%esp) --> "Room Number: "
0x08048885 <+101>: call 0x8048490 <printf@plt>
0x0804888a <+106>: mov 0x804b080,%eax
0x0804888f <+111>: mov %eax,(%esp)
0x08048892 <+114>: call 0x80484a0 <fflush@plt>
0x08048897 <+119>: mov 0x804b060,%eax
0x0804889c <+124>: mov %eax,0x8(%esp)
0x080488a0 <+128>: movl $0x10,0x4(%esp) --> read 16 bytes
0x080488a8 <+136>: lea -0x1c(%ebp),%eax
0x080488ab <+139>: mov %eax,(%esp)
0x080488ae <+142>: call 0x80484c0 <fgets@plt>
0x080488b3 <+147>: mov 0x804b08c,%ebx
0x080488b9 <+153>: lea -0x1c(%ebp),%eax
0x080488bc <+156>: mov %eax,(%esp)
0x080488bf <+159>: call 0x8048530 <atoi@plt>
0x080488c4 <+164>: mov %eax,(%ebx) --> save room number into address room
0x080488c6 <+166>: movl $0x80496bc,(%esp)
0x080488cd <+173>: call 0x80484f0 <puts@plt> "Booked a room!"
0x080488d2 <+178>: mov 0x804b080,%eax
0x080488d7 <+183>: mov %eax,(%esp)
0x080488da <+186>: call 0x80484a0 <fflush@plt>
0x080488df <+191>: mov -0xc(%ebp),%eax
0x080488e2 <+194>: xor %gs:0x14,%eax
0x080488e9 <+201>: je 0x80488f0 <book_room+208>
0x080488eb <+203>: call 0x80484d0 <__stack_chk_fail@plt>
0x080488f0 <+208>: add $0x34,%esp
0x080488f3 <+211>: pop %ebx
0x080488f4 <+212>: pop %ebp
0x080488f5 <+213>: ret
End of assembler dump.
(gdb)
查看堆结构,发现前四个字节储存的就是room_nummber
(gdb) x/100wx room
0x804c008: 0x00000001(int) 0x61616161 0x00000a61 0x00000000
0x804c018: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c028: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c038: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c048: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c058: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c068: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c078: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c088: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c098: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0a8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0b8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0c8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0d8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0e8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c0f8: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c108: 0x00000000 0x00020ef9 0x00000000 0x00000000
0x804c118: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c128: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c138: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c148: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c158: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c168: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c178: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c188: 0x00000000 0x00000000 0x00000000 0x00000000
主要的问题在print_booking中,这个函数里调用了print_name函数
(gdb) disass print_booking
Dump of assembler code for function print_booking:
0x080489a5 <+0>: push %ebp
0x080489a6 <+1>: mov %esp,%ebp
0x080489a8 <+3>: sub $0x28,%esp
0x080489ab <+6>: mov %gs:0x14,%eax
0x080489b1 <+12>: mov %eax,-0xc(%ebp)
0x080489b4 <+15>: xor %eax,%eax
0x080489b6 <+17>: mov 0x804b088,%eax --> pointer suite
0x080489bb <+22>: test %eax,%eax
0x080489bd <+24>: jne 0x80489e6 <print_booking+65>
0x080489bf <+26>: mov 0x804b08c,%eax
0x080489c4 <+31>: test %eax,%eax
0x080489c6 <+33>: jne 0x80489e6 <print_booking+65>
0x080489c8 <+35>: movl $0x80496cb,(%esp)
0x080489cf <+42>: call 0x8048490 <printf@plt>
0x080489d4 <+47>: mov 0x804b080,%eax
0x080489d9 <+52>: mov %eax,(%esp)
0x080489dc <+55>: call 0x80484a0 <fflush@plt>
0x080489e1 <+60>: jmp 0x8048a71 <print_booking+204>
0x080489e6 <+65>: mov 0x804b088,%eax --> pointer suite
0x080489eb <+70>: test %eax,%eax
0x080489ed <+72>: je 0x8048a2c <print_booking+135>
0x080489ef <+74>: mov 0x804b088,%eax
0x080489f4 <+79>: mov (%eax),%eax -->address of print_name function in suite
0x080489f6 <+81>: mov 0x804b088,%edx
0x080489fc <+87>: add $0x4,%edx
0x080489ff <+90>: mov %edx,(%esp) --> location of string for suite name
0x08048a02 <+93>: call *%eax --> call print_name function giving it location of suite name **Need to overwrite value of print_name function in suite with address of function flag()
0x08048a04 <+95>: mov 0x804b088,%eax
0x08048a09 <+100>: mov 0x104(%eax),%eax
0x08048a0f <+106>: mov %eax,0x4(%esp)
0x08048a13 <+110>: movl $0x804970a,(%esp)
0x08048a1a <+117>: call 0x8048490 <printf@plt>
0x08048a1f <+122>: mov 0x804b080,%eax
0x08048a24 <+127>: mov %eax,(%esp)
0x08048a27 <+130>: call 0x80484a0 <fflush@plt>
0x08048a2c <+135>: mov 0x804b08c,%eax
0x08048a31 <+140>: test %eax,%eax
0x08048a33 <+142>: je 0x8048a71 <print_booking+204>
0x08048a35 <+144>: mov 0x804b08c,%eax
0x08048a3a <+149>: add $0x4,%eax
0x08048a3d <+152>: mov %eax,0x4(%esp)
0x08048a41 <+156>: movl $0x804971c,(%esp)
0x08048a48 <+163>: call 0x8048490 <printf@plt>
0x08048a4d <+168>: mov 0x804b08c,%eax
0x08048a52 <+173>: mov (%eax),%eax
0x08048a54 <+175>: mov %eax,0x4(%esp)
0x08048a58 <+179>: movl $0x804970a,(%esp)
0x08048a5f <+186>: call 0x8048490 <printf@plt>
0x08048a64 <+191>: mov 0x804b080,%eax
0x08048a69 <+196>: mov %eax,(%esp)
0x08048a6c <+199>: call 0x80484a0 <fflush@plt>
0x08048a71 <+204>: mov -0xc(%ebp),%eax
0x08048a74 <+207>: xor %gs:0x14,%eax
0x08048a7b <+214>: je 0x8048a82 <print_booking+221>
0x08048a7d <+216>: call 0x80484d0 <__stack_chk_fail@plt>
0x08048a82 <+221>: leave
0x08048a83 <+222>: ret
End of assembler dump.
(gdb)
之后的delete_booking()函数主要是free()堆块,利用过程就是首先为suite申请堆块,然后free掉,之后为room申请堆块,nummber处输入flag()地址的十进制,这样suite和room的前四个字节都指向同一个地址,造成room前四个字节地址指针混乱,而suite()的print_name()函数地址被转换为flag()地址。